Snap for 10768428 from fd84ccb43068313fcb8c96a94a1157d20015220b to mainline-conscrypt-release Change-Id: If6dd999ea5a71b1c1f29600fc7ab448a44f3b654
diff --git a/.clang-format b/.clang-format index 2fb833a..30ed2de 100644 --- a/.clang-format +++ b/.clang-format
@@ -1,2 +1,12 @@ +# Defines the Chromium style for automatic reformatting. # http://clang.llvm.org/docs/ClangFormatStyleOptions.html BasedOnStyle: Chromium +# This defaults to 'Auto'. Explicitly set it for a while, so that +# 'vector<vector<int> >' in existing files gets formatted to +# 'vector<vector<int>>'. ('Auto' means that clang-format will only use +# 'int>>' if the file already contains at least one such instance.) +Standard: Cpp11 + +# TODO(crbug.com/1392808): Remove when InsertBraces has been upstreamed into +# the Chromium style (is implied by BasedOnStyle: Chromium). +InsertBraces: true
diff --git a/.gitattributes b/.gitattributes index c772c32..953c317 100644 --- a/.gitattributes +++ b/.gitattributes
@@ -3,6 +3,7 @@ *.c text eol=lf *.cc text eol=lf *.cpp text eol=lf +*.evt text eol=lf *.gn text eol=lf *.gni text eol=lf *.h text eol=lf
diff --git a/.gn b/.gn index c974357..b2bf99d 100644 --- a/.gn +++ b/.gn
@@ -1,35 +1,33 @@ -# Copyright 2016 PDFium Authors. All rights reserved. +# Copyright 2016 The PDFium Authors # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. -buildconfig = "//build/config/BUILDCONFIG.gn" +# TODO(crbug.com/pdfium/1932): Switch back to //build/config/BUILDCONFIG.gn if +# appropriate. +buildconfig = "//build_overrides/BUILDCONFIG.gn" + +# The python interpreter to use by default. On Windows, this will look +# for python3.exe and python3.bat. +script_executable = "python3" default_args = { - v8_extra_library_files = [] - v8_experimental_extra_library_files = [] + # PDFs only need to run JavaScript. + v8_enable_webassembly = false # Turns on compiler optimizations in V8 in Debug build. v8_optimized_debug = true + + # PDFium is currently incompatible with the V8 Sandbox. + # See https://crbug.com/v8/13014 for details. + v8_enable_sandbox = false } -check_targets = [ - ":pdfium", - ":pdfium_embeddertests", - ":pdfium_unittests", - "//constants/*", - "//core/*", - "//fpdfsdk/*", - "//fxbarcode/*", - "//fxjs/*", - "//samples/*", - "//skia/*", - "//testing/:*", - "//testing/fuzzers/*", - "//testing/image_diff/*", - "//third_party:bigint", - "//third_party:fx_agg", - "//third_party:fx_freetype", - "//third_party:pdfium_base", - "//third_party:skia_shared", - "//xfa/*", +no_check_targets = [ + # See https://crbug.com/v8/7330 and/or check if these entries exist in + # Chromium's //.gn file. + "//v8:cppgc_base", + "//v8:v8_internal_headers", + "//v8/src/inspector:inspector", + "//v8/test/cctest:cctest_sources", + "//v8/test/unittests:inspector_unittests_sources", ]
diff --git a/.style.yapf b/.style.yapf new file mode 100644 index 0000000..fdd0723 --- /dev/null +++ b/.style.yapf
@@ -0,0 +1,2 @@ +[style] +based_on_style = yapf
diff --git a/.vpython b/.vpython deleted file mode 100644 index efe51d4..0000000 --- a/.vpython +++ /dev/null
@@ -1,38 +0,0 @@ -# This is a vpython "spec" file. -# -# It describes patterns for python wheel dependencies of the python scripts in -# the chromium repo, particularly for dependencies that have compiled components -# (since pure-python dependencies can be easily vendored into third_party). -# -# When vpython is invoked, it finds this file and builds a python VirtualEnv, -# containing all of the dependencies described in this file, fetching them from -# CIPD (the "Chrome Infrastructure Package Deployer" service). Unlike `pip`, -# this never requires the end-user machine to have a working python extension -# compilation environment. All of these packages are built using: -# https://chromium.googlesource.com/infra/infra/+/master/infra/tools/dockerbuild/ -# -# All python scripts in the repo share this same spec, to avoid dependency -# fragmentation. -# -# If you have depot_tools installed in your $PATH, you can invoke python scripts -# in this repo by running them as you normally would run them, except -# substituting `vpython` instead of `python` on the command line, e.g.: -# vpython path/to/script.py some --arguments -# -# Read more about `vpython` and how to modify this file here: -# https://chromium.googlesource.com/infra/infra/+/master/doc/users/vpython.md - -python_version: "2.7" - -# Used by build/toolchain/win/tool_wrapper.py -wheel: < - name: "infra/python/wheels/pypiwin32/${vpython_platform}" - version: "version:219" - match_tag: < - platform: "win32" - > - match_tag: < - platform: "win_amd64" - > -> -
diff --git a/.vpython3 b/.vpython3 new file mode 100644 index 0000000..b6cb1b5 --- /dev/null +++ b/.vpython3
@@ -0,0 +1,54 @@ +# This is a vpython "spec" file. +# +# It describes patterns for python wheel dependencies of the python scripts in +# the chromium repo, particularly for dependencies that have compiled components +# (since pure-python dependencies can be easily vendored into third_party). +# +# When vpython is invoked, it finds this file and builds a python VirtualEnv, +# containing all of the dependencies described in this file, fetching them from +# CIPD (the "Chrome Infrastructure Package Deployer" service). Unlike `pip`, +# this never requires the end-user machine to have a working python extension +# compilation environment. All of these packages are built using: +# https://chromium.googlesource.com/infra/infra/+/main/infra/tools/dockerbuild/ +# +# All python scripts in the repo share this same spec, to avoid dependency +# fragmentation. +# +# If you have depot_tools installed in your $PATH, you can invoke python scripts +# in this repo by running them as you normally would run them, except +# substituting `vpython` instead of `python` on the command line, e.g.: +# vpython path/to/script.py some --arguments +# +# Read more about `vpython` and how to modify this file here: +# https://chromium.googlesource.com/infra/infra/+/main/doc/users/vpython.md + +python_version: "3.8" + +# Used by build/skia_gold_common/output_managerless_skia_gold_session.py +# Used by tools/code_coverage/coverage.py +wheel: < + name: "infra/python/wheels/six-py2_py3" + version: "version:1.15.0" +> + +# Used by build/util/lib/results/result_sink.py +wheel: < + name: "infra/python/wheels/certifi-py2_py3" + version: "version:2021.5.30" +> +wheel: < + name: "infra/python/wheels/charset_normalizer-py3" + version: "version:2.0.4" +> +wheel: < + name: "infra/python/wheels/idna-py2_py3" + version: "version:2.10" +> +wheel: < + name: "infra/python/wheels/requests-py2_py3" + version: "version:2.26.0" +> +wheel: < + name: "infra/python/wheels/urllib3-py2_py3" + version: "version:1.26.6" +>
diff --git a/AUTHORS b/AUTHORS index 3c97237..f8e3ed9 100644 --- a/AUTHORS +++ b/AUTHORS
@@ -7,48 +7,39 @@ # Organization <fnmatch pattern> # # See python fnmatch module documentation for more information. +# +# Please keep the list sorted. -Andrey Khalyavin <halyavin@chromium.org> +# BEGIN individuals section. +Abdelkarim Sellamna <abdelkarim.se@gmail.com> +Aleksei Skotnikov <fineaskotnikov@gmail.com> Antonio Gomes <tonikitoo@igalia.com> -Brett Wilson <brettw@chromium.org> -Bruce Dawson <brucedawson@chromium.org> Chery Cherian <cherycherian@gmail.com> Claudio DeSouza <claudiomdsjr@gmail.com> -Chris Palmer <palmer@chromium.org> -Dan Sinclair <dsinclair@chromium.org> +Dan Ilan <danilan@gmail.com> Felix Kauselmann <licorn@gmail.com> -Finnur Thorarinsson <finnur@chromium.org> GiWan Go <gogil@stealien.com> -Henrique Nakashima <hnakashima@chromium.org> Huy Ngo <huyna89@gmail.com> Jiang Jiang <jiangj@opera.com> -Jochen Eisinger <jochen@chromium.org> -John Abd-El-Malek <jam@chromium.org> -Julien Tinnes <jln@chromium.org> Ke Liu <stackexploit@gmail.com> -Kostya Serebryany <kcc@chromium.org> -Lei Zhang <thestig@chromium.org> -Lucas Nihlen <luken@chromium.org> Luật Nguyễn <manhluat93.php@gmail.com> -Matt Giuca <mgiuca@chromium.org> +Manuel Geißer <geisserml@gmail.com> Michael Doppler <m.doppler@gmail.com> Miklos Vajna <vmiklos@vmiklos.hu> Minh Trần <myoki.crystal@gmail.com> -Nico Weber <thakis@chromium.org> -Nicolás Peña <npm@chromium.org> -Peter Kasting <pkasting@chromium.org> +Peter Varga <pvarga@inf.u-szeged.hu> Ralf Sippl <ralf.sippl@gmail.com> -Raymes Khoury <raymes@chromium.org> -Reid Kleckner <rnk@chromium.org> -Ryan Harrison <rharrison@chromium.org> +Robert Collyer <rcollyer99@gmail.com> Ryan Wiley <wileyrr@gmail.com> -Robert Sesek <rsesek@chromium.org> -Sam Clegg <sbc@chromium.org> -Thomas Sepez <tsepez@chromium.org> +Stephan Hartmann <stha09@googlemail.com> +Tibor Dusnoki <tdusnoki@inf.u-szeged.hu> Wang Qing <wangqing-hf@loongson.cn> Zhuo Qingliang <zhuo.dev@gmail.com> +# END individuals section. -Collabora Ltd. <*@collabora.co.uk> +# BEGIN organizations section. +Ada Logics Ltd. <*@adalogics.com> +Collabora Ltd. <*@collabora.com> DocsCorp Pty Ltd. <*@docscorp.com> Dropbox <*@dropbox.com> Foxit Software Inc <*@foxitsoftware.com> @@ -57,3 +48,5 @@ Loongson Technology Corporation Limited. <*@loongson.cn> Microsoft <*@microsoft.com> PSPDFKit GmbH <*@pspdfkit.com> +The Chromium Authors <*@chromium.org> +# END organizations section.
diff --git a/Android.bp b/Android.bp index 4af2504..85f449b 100644 --- a/Android.bp +++ b/Android.bp
@@ -109,10 +109,6 @@ name: "libpdfium", defaults: ["pdfium-core"], - header_libs: [ - "libpdfium-constants", - ], - whole_static_libs: [ "libpdfium-fpdfsdk", ], @@ -122,6 +118,7 @@ static_libs: [ "libpdfium-agg", "libpdfium-cmaps", + "libpdfium-constants", "libpdfium-edit", "libpdfium-fdrm", "libpdfium-font",
diff --git a/BUILD.gn b/BUILD.gn index 62f09e5..cb1da47 100644 --- a/BUILD.gn +++ b/BUILD.gn
@@ -1,10 +1,17 @@ -# Copyright 2016 The Chromium Authors. All rights reserved. +# Copyright 2016 The PDFium Authors # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. +import("//build/config/clang/clang.gni") +import("//build/config/gclient_args.gni") import("//testing/test.gni") import("pdfium.gni") +group("default") { + testonly = true + deps = [ ":pdfium_all" ] +} + group("freetype_common") { public_deps = [] if (pdf_bundle_freetype) { @@ -16,12 +23,10 @@ config("pdfium_common_config") { cflags = [] + cflags_cc = [] ldflags = [] include_dirs = [ "." ] - defines = [ - "PNG_PREFIX", - "PNG_USE_READ_MACROS", - ] + defines = [] if (!use_system_libopenjpeg2) { defines += [ "OPJ_STATIC" ] @@ -35,13 +40,208 @@ defines += [ "_SKIA_SUPPORT_" ] } - if (pdf_use_skia_paths) { - defines += [ "_SKIA_SUPPORT_PATHS_" ] + if (pdf_use_partition_alloc) { + defines += [ "PDF_USE_PARTITION_ALLOC" ] } if (is_win) { # Assume UTF-8 by default to avoid code page dependencies. cflags += [ "/utf-8" ] + + if (!is_clang) { + cflags += [ + # Warnings permanently disabled: + + # C4091: 'typedef ': ignored on left of 'X' when no variable is + # declared. + # This happens in a number of Windows headers. Dumb. + "/wd4091", + + # C4127: conditional expression is constant + # This warning can in theory catch dead code and other problems, but + # triggers in far too many desirable cases where the conditional + # expression is either set by macros or corresponds some legitimate + # compile-time constant expression (due to constant template args, + # conditionals comparing the sizes of different types, etc.). Some of + # these can be worked around, but it's not worth it. + "/wd4127", + + # C4251: 'identifier' : class 'type' needs to have dll-interface to be + # used by clients of class 'type2' + # This is necessary for the shared library build. + "/wd4251", + + # C4275: non dll-interface class used as base for dll-interface class + # This points out a potential (but rare) problem with referencing static + # fields of a non-exported base, through the base's non-exported inline + # functions, or directly. The warning is subtle enough that people just + # suppressed it when they saw it, so it's not worth it. + "/wd4275", + + # C4312 is a VS 2015 64-bit warning for integer to larger pointer. + # TODO(brucedawson): fix warnings, crbug.com/554200 + "/wd4312", + + # C4324 warns when padding is added to fulfill alignas requirements, + # but can trigger in benign cases that are difficult to individually + # suppress. + "/wd4324", + + # C4351: new behavior: elements of array 'array' will be default + # initialized + # This is a silly "warning" that basically just alerts you that the + # compiler is going to actually follow the language spec like it's + # supposed to, instead of not following it like old buggy versions did. + # There's absolutely no reason to turn this on. + "/wd4351", + + # C4355: 'this': used in base member initializer list + # It's commonly useful to pass |this| to objects in a class' initializer + # list. While this warning can catch real bugs, most of the time the + # constructors in question don't attempt to call methods on the passed-in + # pointer (until later), and annotating every legit usage of this is + # simply more hassle than the warning is worth. + "/wd4355", + + # C4503: 'identifier': decorated name length exceeded, name was + # truncated + # This only means that some long error messages might have truncated + # identifiers in the presence of lots of templates. It has no effect on + # program correctness and there's no real reason to waste time trying to + # prevent it. + "/wd4503", + + # Warning C4589 says: "Constructor of abstract class ignores + # initializer for virtual base class." Disable this warning because it + # is flaky in VS 2015 RTM. It triggers on compiler generated + # copy-constructors in some cases. + "/wd4589", + + # C4611: interaction between 'function' and C++ object destruction is + # non-portable + # This warning is unavoidable when using e.g. setjmp/longjmp. MSDN + # suggests using exceptions instead of setjmp/longjmp for C++, but + # Chromium code compiles without exception support. We therefore have to + # use setjmp/longjmp for e.g. JPEG decode error handling, which means we + # have to turn off this warning (and be careful about how object + # destruction happens in such cases). + "/wd4611", + + # Warnings to evaluate and possibly fix/reenable later: + + "/wd4100", # Unreferenced formal function parameter. + "/wd4121", # Alignment of a member was sensitive to packing. + "/wd4244", # Conversion: possible loss of data. + "/wd4505", # Unreferenced local function has been removed. + "/wd4510", # Default constructor could not be generated. + "/wd4512", # Assignment operator could not be generated. + "/wd4610", # Class can never be instantiated, constructor required. + "/wd4838", # Narrowing conversion. Doesn't seem to be very useful. + "/wd4995", # 'X': name was marked as #pragma deprecated + "/wd4996", # Deprecated function warning. + + # These are variable shadowing warnings that are new in VS2015. We + # should work through these at some point -- they may be removed from + # the RTM release in the /W4 set. + "/wd4456", + "/wd4457", + "/wd4458", + "/wd4459", + + # All of our compilers support the extensions below. + "/wd4200", # nonstandard extension used: zero-sized array in + # struct/union + "/wd4201", # nonstandard extension used: nameless struct/union + "/wd4204", # nonstandard extension used : non-constant aggregate + # initializer + + "/wd4221", # nonstandard extension used : 'identifier' : cannot be + # initialized using address of automatic variable + + # http://crbug.com/588506 - Conversion suppressions waiting on Clang + # -Wconversion. + "/wd4245", # 'conversion' : conversion from 'type1' to 'type2', + # signed/unsigned mismatch + + "/wd4267", # 'var' : conversion from 'size_t' to 'type', possible loss + # of + # data + + "/wd4305", # 'identifier' : truncation from 'type1' to 'type2' + "/wd4389", # 'operator' : signed/unsigned mismatch + + "/wd4702", # unreachable code + + # http://crbug.com/848979 - MSVC is more conservative than Clang with + # regards to variables initialized and consumed in different branches. + "/wd4701", # Potentially uninitialized local variable 'name' used + "/wd4703", # Potentially uninitialized local pointer variable 'name' + # used + + # http://crbug.com/848979 - Remaining Clang permitted warnings. + "/wd4661", # 'identifier' : no suitable definition provided for + # explicit + # template instantiation request + + "/wd4706", # assignment within conditional expression + # MSVC is stricter and requires a boolean expression. + + "/wd4715", # 'function' : not all control paths return a value' + # MSVC does not analyze switch (enum) for completeness. + ] + + cflags_cc += [ + # Allow "noexcept" annotations even though we compile with exceptions + # disabled. + "/wd4577", + ] + + if (current_cpu == "x86") { + cflags += [ + # VC++ 2015 changes 32-bit size_t truncation warnings from 4244 to + # 4267. Example: short TruncTest(size_t x) { return x; } + # Since we disable 4244 we need to disable 4267 during migration. + # TODO(jschuh): crbug.com/167187 fix size_t to int truncations. + "/wd4267", + ] + + if (msvc_use_sse2) { + cflags += [ "/arch:SSE2" ] + } + } + } + } + + if (is_clang) { + # Override -Wno-c++11-narrowing. + cflags += [ "-Wc++11-narrowing" ] + + # TODO(crbug.com/1213098): Remove once this is in //build. + cflags += [ "-Wdeprecated-copy" ] + + # May flag some issues when converting int to size_t. + cflags += [ "-Wtautological-unsigned-zero-compare" ] + + # Catch misuse of cppgc in XFA. + if (pdf_enable_xfa && clang_use_chrome_plugins) { + cflags += [ + "-Xclang", + "-add-plugin", + "-Xclang", + "blink-gc-plugin", + ] + } + } + + if (!is_win && !is_clang) { + cflags += [ + # Override -Wno-narrowing for GCC. + "-Wnarrowing", + + # GCC assumes that control can get past an exhaustive switch and then + # warns if there's no return there. + "-Wno-return-type", + ] } } @@ -72,10 +272,6 @@ } } } - - if (pdf_use_win32_gdi) { - defines += [ "PDFIUM_PRINT_TEXT_WITH_GDI" ] - } } config("pdfium_core_config") { @@ -86,21 +282,27 @@ "//build/config/compiler:noshadowing", ] defines = [] - if (is_linux) { - if (current_cpu == "x64") { - defines += [ "_FX_CPU_=_FX_X64_" ] - cflags += [ "-fPIC" ] - } else if (current_cpu == "x86") { - defines += [ "_FX_CPU_=_FX_X86_" ] - } - } if (is_win) { cflags += [ "/wd4324", "/wd4577", ] } - configs += [ "//build/config/compiler:no_size_t_to_int_warning" ] +} + +config("pdfium_strict_config") { + configs = [ + ":pdfium_core_config", + "//build/config/compiler:wexit_time_destructors", + "//build/config/compiler:wglobal_constructors", + ] +} + +config("pdfium_noshorten_config") { + cflags = [] + if (is_clang) { + cflags += [ "-Wshorten-64-to-32" ] + } } source_set("pdfium_public_headers_impl") { @@ -122,6 +324,7 @@ "public/fpdf_progressive.h", "public/fpdf_save.h", "public/fpdf_searchex.h", + "public/fpdf_signature.h", "public/fpdf_structtree.h", "public/fpdf_sysfontinfo.h", "public/fpdf_text.h", @@ -139,8 +342,9 @@ } component("pdfium") { + output_name = "pdfium" libs = [] - configs += [ ":pdfium_core_config" ] + configs += [ ":pdfium_strict_config" ] public_configs = [ ":pdfium_public_config" ] deps = [ @@ -180,7 +384,7 @@ } if (is_mac) { - libs += [ + frameworks = [ "AppKit.framework", "CoreFoundation.framework", ] @@ -191,24 +395,16 @@ complete_static_lib = true configs -= [ "//build/config/compiler:thin_archive" ] } - - if (is_component_build) { - deps += [ "testing/fuzzers:fuzzer_impls" ] - } } -# Targets below this are only visible within this file (and to the -# top-level gn_visibility target used to help gn_all build everything). -visibility = [ - ":*", - "//:gn_visibility", -] +# Targets below this are only visible within this file. +visibility = [ ":*" ] group("pdfium_unittest_deps") { testonly = true public_deps = [ "core/fxcrt", - "testing:test_support", + "testing:unit_test_support", "//testing/gmock", "//testing/gtest", ] @@ -238,7 +434,6 @@ "core/fxcrt:unittests", "core/fxge:unittests", "fpdfsdk:unittests", - "testing:test_support", "testing:unit_test_support", "//testing/gmock", "//testing/gtest", @@ -255,18 +450,20 @@ "fxjs:unittests", "//v8", ] - } - if (pdf_enable_xfa) { - deps += [ - "fxbarcode:unittests", - "xfa/fde:unittests", - "xfa/fgas:unittests", - "xfa/fgas/layout:unittests", - "xfa/fxfa:unittests", - "xfa/fxfa/fm2js:unittests", - "xfa/fxfa/parser:unittests", - ] + if (pdf_enable_xfa) { + deps += [ + "core/fxcrt/css:unittests", + "fxbarcode:unittests", + "xfa/fde:unittests", + "xfa/fgas/crt:unittests", + "xfa/fgas/font:unittests", + "xfa/fgas/layout:unittests", + "xfa/fxfa:unittests", + "xfa/fxfa/formcalc:unittests", + "xfa/fxfa/parser:unittests", + ] + } } } @@ -276,7 +473,6 @@ ":pdfium_public_headers", "core/fxcrt", "testing:embedder_test_support", - "testing:test_support", "third_party:pdfium_base_test_support", "//testing/gmock", "//testing/gtest", @@ -293,6 +489,7 @@ testonly = true sources = [ "testing/embedder_test_main.cpp" ] deps = [ + ":pdfium_embeddertest_deps", "core/fpdfapi/edit:embeddertests", "core/fpdfapi/parser:embeddertests", "core/fpdfapi/render:embeddertests", @@ -300,8 +497,8 @@ "core/fxcrt", "core/fxge:embeddertests", "fpdfsdk:embeddertests", + "fpdfsdk/formfiller:embeddertests", "fpdfsdk/pwl:embeddertests", - "testing:test_support", "testing/image_diff", "//testing/gmock", "//testing/gtest", @@ -336,14 +533,12 @@ testonly = true sources = [ "testing/image_diff/image_diff.cpp" ] deps = [ - ":pdfium", "core/fxcrt", + "testing:path_service", "testing/image_diff", "//build/win:default_exe_manifest", ] - configs -= [ "//build/config/compiler:chromium_code" ] - configs += [ "//build/config/compiler:no_chromium_code" ] - configs += [ ":pdfium_core_config" ] + configs += [ ":pdfium_strict_config" ] } if (pdf_is_standalone) { @@ -372,3 +567,16 @@ ] } } + +# Makes additional targets reachable only for "gn check". These are not always +# built by the "all" Ninja target, which uses the "default" group, which in turn +# depends on the "pdfium_all" group. +group("gn_check") { + deps = [] + + # TODO(crbug.com/pdfium/1832): Remove !is_android when //third_party/expat is + # available. + if (defined(checkout_skia) && checkout_skia && !is_android) { + deps += [ "//skia" ] + } +}
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..f23251b --- /dev/null +++ b/CONTRIBUTING.md
@@ -0,0 +1,205 @@ +# CONTRIBUTING +In general, we follow the +[Chromium Contributing](https://chromium.googlesource.com/chromium/src/+/main/docs/contributing.md) +guidelines in PDFium. The code review process, and the build tools are all very +similar to Chromium. The PDFium +[README](https://pdfium.googlesource.com/pdfium/+/refs/heads/main/README.md) +outlines specific build and test information for PDFium. + +This document focuses on how the PDFium project operates and how we’d like it +to operate in the future. This is a living document, please file bugs if you +think there are changes/updates which could be put in place to make it easier +to contribute to PDFium. + +## Communication +When writing a new feature or fixing an existing bug, get a second opinion +before investing effort in coding. Coordinating up front makes it much easier +to avoid frustration later on. + +If it‘s a new feature, or updating existing code, first propose it to the +[mailing list](https://groups.google.com/forum/#!forum/pdfium). + + * If a change needs further context outside the CL, it should be tracked in + the [bug system](https://bugs.chromium.org/p/pdfium). Bugs are the right + place for long histories, discussion and debate, attaching screenshots, and + linking to other associated bugs. Bugs are unnecessary for changes isolated + enough to not need any of these. + * If the work being implemented is especially complex or large a design + document may be warranted. The document should be linked to the filled bug + and be set to publicly viewable. + * If there isn't a bug and there should be one, please file a new bug. + * Just because there is a bug in the bug system doesn't necessarily mean that + a patch will be accepted. + +## Public APIs +The public API of PDFium has grown over time. There are multiple mechanisms in +place to support this growth from the stability requirements to the versioning +fields. Along with those there are several other factors to be considered when +adding public APIs. + + * _Consistency_. We try to keep the APIs consistent with each other, this + includes things like naming, parameter ordering and how parameters are + handled. + * _Generality_. PDFium is used in several places outside the browser. This + could be server side, or in user applications. APIs should be designed to + work in the general case, or such that they can be expanded to the general + case if possible. + * _Documentation_. All public APIs should be documented to include information + on ownership of passed parameters, valid values being provided, error + conditions and return values. + * _Differentiate error conditions_. If at all possible, it should be possible + to tell the difference between a valid failure and an error. + * _Avoid global state_. APIs should receive the objects to be operated on + instead of assuming they exist in a global context. + +### Stability +There are a lot of consumers of PDFium outside of Chromium. These include +LibreOffice, Android and offline conversion tooling. As such, a lot of care is +taken around the code in the +[public](https://pdfium.googlesource.com/pdfium/+/refs/heads/main/public/) +folder. When planning on changing the public API, the change should be preceded +by a bug being created and an email to the mailing list to gather feedback from +other PDFium embedders. + +The only stability guarantees that PDFium provides are around the APIs in the +public folder. Any other interface in the system can be changed without notice. +If there are features needed which are not exposed through the public headers +you'll need to file a bug to get it added to the public APIs. + +#### Experimental +All APIs start as Experimental. The experimental status is a documentation tag +which is added to the API, the first line of the API documentation should be +`// Experimental API.` + +Experimental APIs may be changed or removed entirely without formal notice to +the community. + +#### Stable +APIs eventually graduate to stable. This is done by removing the +`// Experimental API.` marker in the documentation. We endeavor to not change +stable APIs without notice to the community. + +NOTE, the process of migrating from experimental to stable isn’t well defined +at this point. We have experimental APIs which have been that way for multiple +years. We should work to better define how this transition happens. + +#### Deprecated +If the API is retired, it is marked as deprecated and will eventually be removed. +API deprecation should, ideally, come with a better replacement API and have a +6-12 months deprecation period. The pending removal should be recorded in the +documentation comment for the API and should also be recorded in the README with +the target removal timeframe. All deprecations should have an associated bug +attached to them. + +### Versioning +In order to allow the public API to expand there are `version` fields in some +structures. When the versioned structures are expanded those version fields +need to be incremented to cover the new additions. The code then needs to guard +against the structure being received having the required version number in +order to validate the new additions are available. + +## Trybot Access +Changes must pass the try bots before they are merged into the repo. For your +first few CLs the try bots will need to be triggered by a committer. After +you've submitted 2-3 CLs you can request try bot access by emailing one of the +OWNERS and requesting try bot access. This will allow you to trigger the bots +on your own changes without needing a committer. + +## Committers +All changes committed to PDFium must be reviewed by a committer. Committers +have done significant work in the PDFium code base and have a good overall +understanding of the system. + +Contributors can become committers as they exhibit a strong understanding +of the code base. There is a general requirement for ~10 non-trivial CLs to be +written by the contributor before being considered for committership. The +contributor is then nominated by an existing committer and if the nomination is +accepted by two other committers they receive committer status. + +## OWNERS +The OWNERS files list long time committers to the project and have a broad +understanding of the code base and how the various pieces interact. In the +event of a code review stalling with a committer, the OWNERS are the first line +of escalation. The OWNERS files inherit up the tree, so an OWNER in a top-level +folder has OWNERS in the folders subdirectories. + +There are a limited number of OWNERS files in PDFium at this time due to the +inherent interconnectedness of the code. We are hoping to expand the number of +OWNERS files to make them more targeted as the code quality progresses. + +Committers can be added to OWNERS files when they exhibit a strong +understanding of the PDFium code base. This typically involves a combination of +significant CLs, code review on other contributor CLs, and working with the +other OWNERs to work through design and development considerations for the code. +An OWNER must be committed to upholding the principles for the long term health +of the project, take on a responsibility for reviewing future work, and +mentor new contributors. Once you are a committer, you should feel free to reach +out to the OWNERS who have reviewed your patches to ask what else they’d like to +see from you to be comfortable nominating you as an OWNER. Once nominated, +OWNERS are added or removed by rough consensus of the existing OWNERS. + +## Escalations +There are times when reviews stall due to differences between reviewers, +developers and OWNERS. If this happens, please escalate the situation to one of +the people in the top-level OWNERS file (or another of the owners if already +discussing with a top-level owner). If the disagreement has moved up through +all the OWNERS files in the PDFium repo, the escalation should then proceed to +the Chromium +[ATL_OWNERS](https://chromium.googlesource.com/chromium/src/+/refs/heads/main/ATL_OWNERS) +as the final deciders. + +The +[Standard of Code Review](https://google.github.io/eng-practices/review/reviewer/standard.html) +document has some good guidance on resolving conflicts during code review. + +## CLA +All contributors must complete the Google contributor license agreement. For +individual contributors, please complete the +[Individual Contributor License Agreement](https://cla.developers.google.com/about/google-individual?csw=1) +online. Corporate contributors must fill out the +[Corporate Contributor License Agreement](https://cla.developers.google.com/about/google-corporate?csw=1) +and send it to us as described on that page. + +Your first CL should add yourself to the +[AUTHORS](https://pdfium.googlesource.com/pdfium/+/refs/heads/main/AUTHORS) +file (unless you’re covered by one of the blanket entries). + +### External contributor checklist for reviewers +Before LGTMing a change, ensure that the contribution can be accepted: + * Definition: The "author" is the email address that owns the code review + request on + [https://pdfium-review.googlesource.com](https://pdfium-review.googlesource.com/) + * Ensure the author is already listed in + [AUTHORS](https://pdfium.googlesource.com/pdfium/+/refs/heads/main/AUTHORS). + In some cases, the author's company might have a wildcard rule + (e.g. \*@google.com). + * If the author or their company is not listed, the CL should include a new + AUTHORS entry. + * Ensure the new entry is reviewed by a reviewer who works for Google. + * Contributor License Agreement can be verified by Googlers at + [http://go/cla](http://go/cla) + * If there is a corporate CLA for the author‘s company, it must list the + person explicitly (or the list of authorized contributors must say + something like "All employees"). If the author is not on their company’s + roster, do not accept the change. + +## Legacy Code +The PDFium code base has been around in one form or another for a long time. As +such, there is a lot of legacy hidden in the existing code. There are surprising +interactions and untested corners of the code. We are actively working on +increasing code coverage on the existing code, and especially welcome additions +which move the coverage upwards. All new code should come with tests (either +unit tests or integration tests depending on the feature). + +As part of this legacy nature, there is a good chance the code you’re working +with wasn’t designed to do what you need it to do. There are often refactorings +and bug fixes that end up happening along with feature development. Those +fixes/refactorings should be pulled out to their own changes with the +appropriate tests. This will make reviews a lot easier as, currently, it can be +hard to tell if there are far reaching effects of a given change. + +There is a lot of existing technical debt that is being paid down in PDFium, +anything we can do here to make future development easier is a great benefit to +the project. This debt means means code reviews can take a bit longer if +research is needed to determine how a feature change will interact with the +rest of the system.
diff --git a/DEPS b/DEPS index a939282..e5aa4d8 100644 --- a/DEPS +++ b/DEPS
@@ -1,132 +1,429 @@ use_relative_paths = True +gclient_gn_args_file = 'build/config/gclient_args.gni' +gclient_gn_args = [ + 'checkout_skia', +] + vars = { # By default, we should check out everything needed to run on the main - # chromium waterfalls. This var can be also be set to "small", in order - # to skip things are not strictly needed to build chromium for development - # purposes. + # pdfium waterfalls. This var can be also be set to 'small', in order to skip + # things are not strictly needed to build pdfium for development purposes, + # by adding the following line to the .gclient file inside a solutions entry: + # "custom_vars": { "checkout_configuration": "small" }, + # Similarly, this var can be set to 'minimal' to also skip the Skia and V8 + # checkouts for the smallest possible checkout, where some features will not + # work. 'checkout_configuration': 'default', - 'checkout_instrumented_libraries': 'checkout_linux and checkout_configuration != "small"', + 'checkout_instrumented_libraries': 'checkout_linux and checkout_configuration != "small" and checkout_configuration != "minimal"', + + 'checkout_skia': 'checkout_configuration != "minimal"', + + 'checkout_testing_corpus': 'checkout_configuration != "small" and checkout_configuration != "minimal"', + + 'checkout_v8': 'checkout_configuration != "minimal"', + + # By default, download the fuchsia sdk from the public sdk directory. + 'fuchsia_sdk_cipd_prefix': 'fuchsia/sdk/gn/', 'chromium_git': 'https://chromium.googlesource.com', 'pdfium_git': 'https://pdfium.googlesource.com', + 'skia_git': 'https://skia.googlesource.com', - 'android_ndk_revision': '27c0a8d090c666a50e40fceb4ee5b40b1a2d3f87', - 'binutils_revision': '01aa7745b0bab64ae22600f09fd6483c60f22ebf', - 'build_revision': '1bee638a8c4a9481ea06df4982d69488d0a5626d', - 'buildtools_revision': '1f38b432e5630619f3aba0a22b9b63d606aee35a', - 'catapult_revision': 'f7d73bb520283d2a06b8fde8a1b02aa33414fcd0', - 'clang_revision': '42fbdfef1ce265b09dc6bda2ed90d83324c97481', - 'code_coverage_revision': 'c7a868bacaccf4f52848e04564fb7de0671e0727', - 'depot_tools_revision': 'e9730d75a00548a22e4392567243969d85c02dd4', - 'freetype_revision': 'e5038be70414cf66da6c4d5ce4e30375884c30d8', - 'gtest_revision': '5395345ca4f0c596110188688ed990e0de5a181c', - 'icu_revision': 'dbd3825b31041d782c5b504c59dcfb5ac7dda08c', - 'instrumented_lib_revision': '4dca59c6a614b08b394ed6154a8fcded9298b07e', - 'jinja2_revision': 'b41863e42637544c2941b574c7877d3e1f663e25', - 'jpeg_turbo_revision': 'ce0e57e8e636f5132fe6f0590a4dba91f92fd935', - 'markupsafe_revision': '8f45f5cfa0009d2a70589bcda0349b8cb2b72783', - 'pdfium_tests_revision': '02dd653ec62649b6f1aa4e4526071cc32d903f54', - 'skia_revision': 'd50cc95872a8a832faea0154f7ea1fd56cebc775', - 'tools_memory_revision': 'f7b00daf4df7f6c469f5fbc68d7f40f6bd15d6e6', - 'trace_event_revision': '81c050f857a0e3c960cfd87f37e3d30d2ef78718', - 'v8_revision': 'cd34145326def51cb6dcf87aed7d0caf9f62bb4f', - 'yasm_source_revision': '720b70524a4424b15fc57e82263568c8ba0496ad', - 'zlib_revision': '814da1f383b625955149c3845db62af3f29a4ffe', + # Three lines of non-changing comments so that + # the commit queue can handle CLs rolling abseil + # and whatever else without interference from each other. + 'abseil_revision': '20c8ae002db022653b94e80dec69306558818ebf', + # Three lines of non-changing comments so that + # the commit queue can handle CLs rolling android_ndk + # and whatever else without interference from each other. + 'android_ndk_revision': '8388a2be5421311dc75c5f937aae13d821a27f3d', + # Three lines of non-changing comments so that + # the commit queue can handle CLs rolling build + # and whatever else without interference from each other. + 'build_revision': 'c44ccbfc028a136e7d39bf79e45a92a91d7b5beb', + # Three lines of non-changing comments so that + # the commit queue can handle CLs rolling buildtools + # and whatever else without interference from each other. + 'buildtools_revision': '3ee69a5c6bc8d115dea09bbf8e536f529e7e12a8', + # Three lines of non-changing comments so that + # the commit queue can handle CLs rolling catapult + # and whatever else without interference from each other. + 'catapult_revision': 'ac30cc4bc7d30e574625e1f6a77fba5df0719ed6', + # Three lines of non-changing comments so that + # the commit queue can handle CLs rolling clang format + # and whatever else without interference from each other. + 'clang_format_revision': 'f97059df7f8b205064625cdb5f97b56668a125ef', + # Three lines of non-changing comments so that + # the commit queue can handle CLs rolling clang + # and whatever else without interference from each other. + 'clang_revision': 'f6862472607fa628642713b615a9e119d51bd43d', + # Three lines of non-changing comments so that + # the commit queue can handle CLs rolling code_coverage + # and whatever else without interference from each other. + 'code_coverage_revision': '9b51524c4f7575ee90d9173507e6f13f814d7001', + # Three lines of non-changing comments so that + # the commit queue can handle CLs rolling depot_tools + # and whatever else without interference from each other. + 'depot_tools_revision': 'ab117384e6c0384ba5aab66c13d8f1008d964655', + # Three lines of non-changing comments so that + # the commit queue can handle CLs rolling freetype + # and whatever else without interference from each other. + 'freetype_revision': 'b0a4f99278aa7e14bd1d0d9e40ad28dce543fde6', + # Three lines of non-changing comments so that + # the commit queue can handle CLs rolling Fuchsia sdk + # and whatever else without interference from each other. + 'fuchsia_version': 'version:12.20230330.3.1', + # Three lines of non-changing comments so that + # the commit queue can handle CLs rolling GN CIPD package version + # and whatever else without interference from each other. + 'gn_version': 'git_revision:41fef642de70ecdcaaa26be96d56a0398f95abd4', + # Three lines of non-changing comments so that + # the commit queue can handle CLs rolling gtest + # and whatever else without interference from each other. + 'gtest_revision': 'af29db7ec28d6df1c7f0f745186884091e602e07', + # Three lines of non-changing comments so that + # the commit queue can handle CLs rolling icu + # and whatever else without interference from each other. + 'icu_revision': '1e49ac26ddc712b1ab702f69023cbc57e9ae6628', + # Three lines of non-changing comments so that + # the commit queue can handle CLs rolling instrumented_lib + # and whatever else without interference from each other. + 'instrumented_lib_revision': '0f536d22dbed454b1254c7e6d7130eab28fba1fa', + # Three lines of non-changing comments so that + # the commit queue can handle CLs rolling jinja2 + # and whatever else without interference from each other. + 'jinja2_revision': '264c07d7e64f2874434a3b8039e101ddf1b01e7e', + # Three lines of non-changing comments so that + # the commit queue can handle CLs rolling jpeg_turbo + # and whatever else without interference from each other. + 'jpeg_turbo_revision': 'aa4075f116e4312537d0d3e9dbd5e31096539f94', + # Three lines of non-changing comments so that + # the commit queue can handle CLs rolling libc++ + # and whatever else without interference from each other. + # If you change this, also update the libc++ revision in + # //buildtools/deps_revisions.gni. + 'libcxx_revision': 'ab37483b426c16ce33f8f0064be571513d5a8c34', + # Three lines of non-changing comments so that + # the commit queue can handle CLs rolling libc++abi + # and whatever else without interference from each other. + 'libcxxabi_revision': '4a9d0560b481a96821bec591325b50a5063f4a32', + # Three lines of non-changing comments so that + # the commit queue can handle CLs rolling libpng + # and whatever else without interference from each other. + 'libpng_revision': '805df541c44099bb20d425ac47c666e29b1f7a80', + # Three lines of non-changing comments so that + # the commit queue can handle CLs rolling libunwind + # and whatever else without interference from each other. + 'libunwind_revision': 'f3464caa6aa83a5eb924a5ae3779e974bd1bebf4', + # Three lines of non-changing comments so that + # the commit queue can handle CLs rolling lss + # and whatever else without interference from each other. + 'lss_revision': 'ce877209e11aa69dcfffbd53ef90ea1d07136521', + # Three lines of non-changing comments so that + # the commit queue can handle CLs rolling markupsafe + # and whatever else without interference from each other. + 'markupsafe_revision': '13f4e8c9e206567eeb13bf585406ddc574005748', + # Three lines of non-changing comments so that + # the commit queue can handle CLs rolling nasm_source + # and whatever else without interference from each other. + 'nasm_source_revision': '7fc833e889d1afda72c06220e5bed8fb43b2e5ce', + # Three lines of non-changing comments so that + # the commit queue can handle CLs rolling Ninja CIPD package version + # and whatever else without interference from each other. + 'ninja_version': 'version:2@1.11.1.chromium.6', + # Three lines of non-changing comments so that + # the commit queue can handle CLs rolling partition_allocator + # and whatever else without interference from each other. + 'partition_allocator_revision': '118936d6793d0c259bd9023717d37367a7b04320', + # Three lines of non-changing comments so that + # the commit queue can handle CLs rolling pdfium_tests + # and whatever else without interference from each other. + 'pdfium_tests_revision': 'd1386521f5d606b9110143aa40b23651b17aded2', + # Three lines of non-changing comments so that + # the commit queue can handle CLs rolling resultdb + # and whatever else without interference from each other. + 'resultdb_version': 'git_revision:ebc74d10fa0d64057daa6f128e89f3672eeeec95', + # Three lines of non-changing comments so that + # the commit queue can handle CLs rolling skia + # and whatever else without interference from each other. + 'skia_revision': 'ad459a5b8df474d881209696b3fb4f038e0d3a55', + # Three lines of non-changing comments so that + # the commit queue can handle CLs rolling test_fonts + # and whatever else without interference from each other. + 'test_fonts_revision': '7f51783942943e965cd56facf786544ccfc07713', + # Three lines of non-changing comments so that + # the commit queue can handle CLs rolling tools_memory + # and whatever else without interference from each other. + 'tools_memory_revision': '13f0b81ce581364c5f0f2e9e16d6120073dc56a6', + # Three lines of non-changing comments so that + # the commit queue can handle CLs rolling trace_event + # and whatever else without interference from each other. + 'trace_event_revision': '147f65333c38ddd1ebf554e89965c243c8ce50b3', + # Three lines of non-changing comments so that + # the commit queue can handle CLs rolling v8 + # and whatever else without interference from each other. + 'v8_revision': 'f66b0bc93b1edc09a6ff66c2e0ae0f2848d90be7', + # Three lines of non-changing comments so that + # the commit queue can handle CLs rolling zlib + # and whatever else without interference from each other. + 'zlib_revision': 'b890619bc2b193b8fbe9c1c053f4cd19a9791d92', } +# Only these hosts are allowed for dependencies in this DEPS file. +# If you need to add a new host, and the new host is not in Chromium's DEPS +# file's allowed_hosts list, contact Chrome infrastructure team. +allowed_hosts = [ + 'chromium.googlesource.com', + 'pdfium.googlesource.com', + 'skia.googlesource.com', +] + deps = { - "base/trace_event/common": - Var('chromium_git') + "/chromium/src/base/trace_event/common.git@" + + 'base/allocator/partition_allocator': + Var('chromium_git') + + '/chromium/src/base/allocator/partition_allocator.git@' + + Var('partition_allocator_revision'), + + 'base/trace_event/common': + Var('chromium_git') + '/chromium/src/base/trace_event/common.git@' + Var('trace_event_revision'), - "build": - Var('chromium_git') + "/chromium/src/build.git@" + Var('build_revision'), + 'build': + Var('chromium_git') + '/chromium/src/build.git@' + Var('build_revision'), - "buildtools": - Var('chromium_git') + "/chromium/src/buildtools.git@" + + 'buildtools': + Var('chromium_git') + '/chromium/src/buildtools.git@' + Var('buildtools_revision'), - "testing/corpus": - Var('pdfium_git') + "/pdfium_tests@" + Var('pdfium_tests_revision'), + 'buildtools/clang_format/script': + Var('chromium_git') + + '/external/github.com/llvm/llvm-project/clang/tools/clang-format.git@' + + Var('clang_format_revision'), - "third_party/android_ndk": { - 'url': Var('chromium_git') + "/android_ndk.git@" + Var('android_ndk_revision'), + 'buildtools/linux64': { + 'packages': [ + { + 'package': 'gn/gn/linux-amd64', + 'version': Var('gn_version'), + } + ], + 'dep_type': 'cipd', + 'condition': 'host_os == "linux"', + }, + + 'buildtools/mac': { + 'packages': [ + { + 'package': 'gn/gn/mac-${{arch}}', + 'version': Var('gn_version'), + } + ], + 'dep_type': 'cipd', + 'condition': 'host_os == "mac"', + }, + + 'buildtools/third_party/libc++/trunk': + Var('chromium_git') + + '/external/github.com/llvm/llvm-project/libcxx.git@' + + Var('libcxx_revision'), + + 'buildtools/third_party/libc++abi/trunk': + Var('chromium_git') + + '/external/github.com/llvm/llvm-project/libcxxabi.git@' + + Var('libcxxabi_revision'), + + 'buildtools/third_party/libunwind/trunk': + Var('chromium_git') + + '/external/github.com/llvm/llvm-project/libunwind.git@' + + Var('libunwind_revision'), + + 'buildtools/win': { + 'packages': [ + { + 'package': 'gn/gn/windows-amd64', + 'version': Var('gn_version'), + } + ], + 'dep_type': 'cipd', + 'condition': 'host_os == "win"', + }, + + 'testing/corpus': { + 'url': Var('pdfium_git') + '/pdfium_tests@' + Var('pdfium_tests_revision'), + 'condition': 'checkout_testing_corpus', + }, + + 'third_party/abseil-cpp': + Var('chromium_git') + '/chromium/src/third_party/abseil-cpp.git@' + + Var('abseil_revision'), + + 'third_party/android_ndk': { + 'url': Var('chromium_git') + '/android_ndk.git@' + + Var('android_ndk_revision'), 'condition': 'checkout_android', }, - "third_party/binutils": - Var('chromium_git') + "/chromium/src/third_party/binutils.git@" + - Var('binutils_revision'), - - "third_party/catapult": { - 'url': Var('chromium_git') + '/catapult.git' + '@' + Var('catapult_revision'), + 'third_party/catapult': { + 'url': Var('chromium_git') + '/catapult.git@' + Var('catapult_revision'), 'condition': 'checkout_android', }, 'third_party/depot_tools': - Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + + Var('chromium_git') + '/chromium/tools/depot_tools.git@' + Var('depot_tools_revision'), - "third_party/freetype/src": + 'third_party/freetype/src': Var('chromium_git') + '/chromium/src/third_party/freetype2.git@' + Var('freetype_revision'), - "third_party/googletest/src": - Var('chromium_git') + '/external/github.com/google/googletest.git' + '@' + + 'third_party/fuchsia-sdk/sdk': { + 'packages': [ + { + 'package': Var('fuchsia_sdk_cipd_prefix') + '${{platform}}', + 'version': Var('fuchsia_version'), + }, + ], + 'condition': 'checkout_fuchsia', + 'dep_type': 'cipd', + }, + + 'third_party/googletest/src': + Var('chromium_git') + '/external/github.com/google/googletest.git@' + Var('gtest_revision'), - "third_party/icu": - Var('chromium_git') + "/chromium/deps/icu.git@" + Var('icu_revision'), + 'third_party/icu': + Var('chromium_git') + '/chromium/deps/icu.git@' + Var('icu_revision'), - "third_party/instrumented_libraries": + 'third_party/instrumented_libraries': Var('chromium_git') + - "/chromium/src/third_party/instrumented_libraries.git@" + + '/chromium/src/third_party/instrumented_libraries.git@' + Var('instrumented_lib_revision'), - "third_party/jinja2": - Var('chromium_git') + "/chromium/src/third_party/jinja2.git@" + + 'third_party/jinja2': + Var('chromium_git') + '/chromium/src/third_party/jinja2.git@' + Var('jinja2_revision'), - "third_party/markupsafe": - Var('chromium_git') + "/chromium/src/third_party/markupsafe.git@" + - Var('markupsafe_revision'), - - "third_party/libjpeg_turbo": - Var('chromium_git') + "/chromium/deps/libjpeg_turbo.git@" + + 'third_party/libjpeg_turbo': + Var('chromium_git') + '/chromium/deps/libjpeg_turbo.git@' + Var('jpeg_turbo_revision'), - "third_party/skia": - Var('chromium_git') + '/skia.git@' + Var('skia_revision'), + 'third_party/libpng': + Var('chromium_git') + '/chromium/src/third_party/libpng.git@' + + Var('libpng_revision'), - "third_party/zlib": - Var('chromium_git') + "/chromium/src/third_party/zlib.git@" + + 'third_party/lss': { + 'url': Var('chromium_git') + '/linux-syscall-support.git' + '@' + Var('lss_revision'), + 'condition': 'checkout_android or checkout_linux', + }, + + 'third_party/markupsafe': + Var('chromium_git') + '/chromium/src/third_party/markupsafe.git@' + + Var('markupsafe_revision'), + + 'third_party/nasm': + Var('chromium_git') + '/chromium/deps/nasm.git@' + + Var('nasm_source_revision'), + + 'third_party/ninja': { + 'packages': [ + { + # https://chrome-infra-packages.appspot.com/p/infra/3pp/tools/ninja + 'package': 'infra/3pp/tools/ninja/${{platform}}', + 'version': Var('ninja_version'), + } + ], + 'dep_type': 'cipd', + }, + + 'third_party/skia': { + 'url': Var('skia_git') + '/skia.git@' + Var('skia_revision'), + 'condition': 'checkout_skia', + }, + + 'third_party/test_fonts': + Var('chromium_git') + '/chromium/src/third_party/test_fonts.git@' + + Var('test_fonts_revision'), + + 'third_party/zlib': + Var('chromium_git') + '/chromium/src/third_party/zlib.git@' + Var('zlib_revision'), - 'third_party/yasm/source/patched-yasm': - Var('chromium_git') + '/chromium/deps/yasm/patched-yasm.git@' + - Var('yasm_source_revision'), + 'tools/clang': + Var('chromium_git') + '/chromium/src/tools/clang@' + Var('clang_revision'), - "tools/clang": - Var('chromium_git') + "/chromium/src/tools/clang@" + Var('clang_revision'), - - "tools/code_coverage": - Var('chromium_git') + "/chromium/src/tools/code_coverage.git@" + + 'tools/code_coverage': + Var('chromium_git') + '/chromium/src/tools/code_coverage.git@' + Var('code_coverage_revision'), - "tools/memory": - Var('chromium_git') + "/chromium/src/tools/memory@" + + 'tools/memory': + Var('chromium_git') + '/chromium/src/tools/memory@' + Var('tools_memory_revision'), - "v8": - Var('chromium_git') + "/v8/v8.git@" + Var('v8_revision'), + 'tools/resultdb': { + 'packages': [ + { + 'package': 'infra/tools/result_adapter/${{platform}}', + 'version': Var('resultdb_version'), + }, + ], + 'dep_type': 'cipd', + }, + + # TODO(crbug.com/pdfium/1650): Set up autorollers for goldctl. + 'tools/skia_goldctl/linux': { + 'packages': [ + { + 'package': 'skia/tools/goldctl/linux-amd64', + 'version': 'eZ3k373CYgRxlu4JKph6e-_7xkP02swy_jePFFMiyIQC', + } + ], + 'dep_type': 'cipd', + 'condition': 'checkout_linux', + }, + + 'tools/skia_goldctl/mac_amd64': { + 'packages': [ + { + 'package': 'skia/tools/goldctl/mac-amd64', + 'version': 'nHUjLIViYsLxRjv-zDdmzqT8p1R3VoyHq5gdGkKeMYwC', + } + ], + 'dep_type': 'cipd', + 'condition': 'checkout_mac', + }, + + 'tools/skia_goldctl/mac_arm64': { + 'packages': [ + { + 'package': 'skia/tools/goldctl/mac-arm64', + 'version': '-mc865SGfJAqreLZM6fkn8tgCJ7u5QLk5zm7r-ZRJ9gC', + } + ], + 'dep_type': 'cipd', + 'condition': 'checkout_mac', + }, + + 'tools/skia_goldctl/win': { + 'packages': [ + { + 'package': 'skia/tools/goldctl/windows-amd64', + 'version': 'iEqqRADI7znrc6pG-MVnc5pBZwD25koILREPC6x2AFAC', + } + ], + 'dep_type': 'cipd', + 'condition': 'checkout_win', + }, + + 'v8': { + 'url': Var('chromium_git') + '/v8/v8.git@' + Var('v8_revision'), + 'condition': 'checkout_v8', + }, + } -recursedeps = [ - # buildtools provides clang_format, libc++, and libc++abi - 'buildtools', -] +recursedeps = [] include_rules = [ # Basic stuff that everyone can use. @@ -135,27 +432,45 @@ '+constants', '+testing', '+third_party/base', + + # Abseil features must be allowlisted explicitly for now. See Chromium's + # //styleguide/c++/c++11.html. Allowed features' headers will be listed + # explicitly here. + '-absl', + '-third_party/abseil-cpp', + '+third_party/abseil-cpp/absl/types/optional.h', + '+third_party/abseil-cpp/absl/types/variant.h', ] specific_include_rules = { # Allow embedder tests to use public APIs. - "(.*embeddertest\.cpp)": [ - "+public", + '(.*embeddertest\.cpp)': [ + '+public', ] } hooks = [ { + # Ensure that the DEPS'd "depot_tools" has its self-update capability + # disabled. + 'name': 'disable_depot_tools_selfupdate', + 'pattern': '.', + 'action': [ 'python3', + 'third_party/depot_tools/update_depot_tools_toggle.py', + '--disable', + ], + }, + { # Case-insensitivity for the Win SDK. Must run before win_toolchain below. 'name': 'ciopfs_linux', 'pattern': '.', 'condition': 'checkout_win and host_os == "linux"', - 'action': [ 'python', - 'pdfium/third_party/depot_tools/download_from_google_storage.py', + 'action': [ 'python3', + 'third_party/depot_tools/download_from_google_storage.py', '--no_resume', '--no_auth', '--bucket', 'chromium-browser-clang/ciopfs', - '-s', 'pdfium/build/ciopfs.sha1', + '-s', 'build/ciopfs.sha1', ] }, { @@ -163,129 +478,177 @@ 'name': 'win_toolchain', 'pattern': '.', 'condition': 'checkout_win', - 'action': ['python', 'pdfium/build/vs_toolchain.py', 'update', '--force'], + 'action': ['python3', 'build/vs_toolchain.py', 'update', '--force'], }, { # Update the Mac toolchain if necessary. 'name': 'mac_toolchain', 'pattern': '.', - 'action': ['python', 'pdfium/build/mac_toolchain.py'], + 'condition': 'checkout_mac', + 'action': ['python3', 'build/mac_toolchain.py'], }, + # Pull dsymutil binaries using checked-in hashes. { - # Pull clang-format binaries using checked-in hashes. - 'name': 'clang_format_win', + 'name': 'dsymutil_mac_arm64', 'pattern': '.', - 'action': [ 'download_from_google_storage', + 'condition': 'host_os == "mac" and host_cpu == "arm64"', + 'action': [ 'python3', + 'third_party/depot_tools/download_from_google_storage.py', '--no_resume', - '--platform=win32', '--no_auth', - '--bucket', 'chromium-clang-format', - '-s', 'pdfium/buildtools/win/clang-format.exe.sha1', + '--bucket', 'chromium-browser-clang', + '-s', 'tools/clang/dsymutil/bin/dsymutil.arm64.sha1', + '-o', 'tools/clang/dsymutil/bin/dsymutil', ], }, { - 'name': 'clang_format_mac', + 'name': 'dsymutil_mac_x64', 'pattern': '.', - 'action': [ 'download_from_google_storage', + 'condition': 'host_os == "mac" and host_cpu == "x64"', + 'action': [ 'python3', + 'third_party/depot_tools/download_from_google_storage.py', '--no_resume', - '--platform=darwin', + '--no_auth', + '--bucket', 'chromium-browser-clang', + '-s', 'tools/clang/dsymutil/bin/dsymutil.x64.sha1', + '-o', 'tools/clang/dsymutil/bin/dsymutil', + ], + }, + # Pull clang-format binaries using checked-in hashes. + { + 'name': 'clang_format_win', + 'pattern': '.', + 'condition': 'host_os == "win"', + 'action': [ 'python3', + 'third_party/depot_tools/download_from_google_storage.py', + '--no_resume', '--no_auth', '--bucket', 'chromium-clang-format', - '-s', 'pdfium/buildtools/mac/clang-format.sha1', + '-s', 'buildtools/win/clang-format.exe.sha1', + ], + }, + { + 'name': 'clang_format_mac_x64', + 'pattern': '.', + 'condition': 'host_os == "mac" and host_cpu == "x64"', + 'action': [ 'python3', + 'third_party/depot_tools/download_from_google_storage.py', + '--no_resume', + '--no_auth', + '--bucket', 'chromium-clang-format', + '-s', 'buildtools/mac/clang-format.x64.sha1', + '-o', 'buildtools/mac/clang-format', + ], + }, + { + 'name': 'clang_format_mac_arm64', + 'pattern': '.', + 'condition': 'host_os == "mac" and host_cpu == "arm64"', + 'action': [ 'python3', + 'third_party/depot_tools/download_from_google_storage.py', + '--no_resume', + '--no_auth', + '--bucket', 'chromium-clang-format', + '-s', 'buildtools/mac/clang-format.arm64.sha1', + '-o', 'buildtools/mac/clang-format', ], }, { 'name': 'clang_format_linux', 'pattern': '.', - 'action': [ 'download_from_google_storage', + 'condition': 'host_os == "linux"', + 'action': [ 'python3', + 'third_party/depot_tools/download_from_google_storage.py', '--no_resume', - '--platform=linux*', '--no_auth', '--bucket', 'chromium-clang-format', - '-s', 'pdfium/buildtools/linux64/clang-format.sha1', + '-s', 'buildtools/linux64/clang-format.sha1', ], }, { # Note: On Win, this should run after win_toolchain, as it may use it. 'name': 'clang', 'pattern': '.', - 'action': ['python', - 'pdfium/tools/clang/scripts/update.py' - ], - }, - { - 'name': 'binutils', - 'pattern': 'src/third_party/binutils', - 'condition': 'host_os == "linux"', - 'action': [ - 'python', - 'pdfium/third_party/binutils/download.py', + 'action': ['python3', + 'tools/clang/scripts/update.py' ], }, { 'name': 'sysroot_arm', 'pattern': '.', 'condition': 'checkout_linux and checkout_arm', - 'action': ['python', 'pdfium/build/linux/sysroot_scripts/install-sysroot.py', + 'action': ['python3', 'build/linux/sysroot_scripts/install-sysroot.py', '--arch=arm'], }, { 'name': 'sysroot_arm64', 'pattern': '.', 'condition': 'checkout_linux and checkout_arm64', - 'action': ['python', 'pdfium/build/linux/sysroot_scripts/install-sysroot.py', + 'action': ['python3', 'build/linux/sysroot_scripts/install-sysroot.py', '--arch=arm64'], }, { 'name': 'sysroot_x86', 'pattern': '.', 'condition': 'checkout_linux and (checkout_x86 or checkout_x64)', - 'action': ['python', 'pdfium/build/linux/sysroot_scripts/install-sysroot.py', + 'action': ['python3', 'build/linux/sysroot_scripts/install-sysroot.py', '--arch=x86'], }, { 'name': 'sysroot_mips', 'pattern': '.', 'condition': 'checkout_linux and checkout_mips', - 'action': ['python', 'pdfium/build/linux/sysroot_scripts/install-sysroot.py', + 'action': ['python3', 'build/linux/sysroot_scripts/install-sysroot.py', '--arch=mips'], }, { 'name': 'sysroot_x64', 'pattern': '.', 'condition': 'checkout_linux and checkout_x64', - 'action': ['python', 'pdfium/build/linux/sysroot_scripts/install-sysroot.py', + 'action': ['python3', 'build/linux/sysroot_scripts/install-sysroot.py', '--arch=x64'], }, { - 'name': 'msan_chained_origins', + 'name': 'test_fonts', + 'pattern': '.', + 'action': [ 'python3', + 'third_party/depot_tools/download_from_google_storage.py', + '--no_resume', + '--extract', + '--no_auth', + '--bucket', 'chromium-fonts', + '-s', 'third_party/test_fonts/test_fonts.tar.gz.sha1', + ], + }, + { + 'name': 'msan_chained_origins_focal', 'pattern': '.', 'condition': 'checkout_instrumented_libraries', - 'action': [ 'python', - 'pdfium/third_party/depot_tools/download_from_google_storage.py', - "--no_resume", - "--no_auth", - "--bucket", "chromium-instrumented-libraries", - "-s", "pdfium/third_party/instrumented_libraries/binaries/msan-chained-origins-trusty.tgz.sha1", + 'action': [ 'python3', + 'third_party/depot_tools/download_from_google_storage.py', + '--no_resume', + '--no_auth', + '--bucket', 'chromium-instrumented-libraries', + '-s', 'third_party/instrumented_libraries/binaries/msan-chained-origins-focal.tgz.sha1', ], }, { - 'name': 'msan_no_origins', + 'name': 'msan_no_origins_focal', 'pattern': '.', 'condition': 'checkout_instrumented_libraries', - 'action': [ 'python', - 'pdfium/third_party/depot_tools/download_from_google_storage.py', - "--no_resume", - "--no_auth", - "--bucket", "chromium-instrumented-libraries", - "-s", "pdfium/third_party/instrumented_libraries/binaries/msan-no-origins-trusty.tgz.sha1", + 'action': [ 'python3', + 'third_party/depot_tools/download_from_google_storage.py', + '--no_resume', + '--no_auth', + '--bucket', 'chromium-instrumented-libraries', + '-s', 'third_party/instrumented_libraries/binaries/msan-no-origins-focal.tgz.sha1', ], }, { # Update LASTCHANGE. 'name': 'lastchange', 'pattern': '.', - 'action': ['python', 'pdfium/build/util/lastchange.py', - '-o', 'pdfium/build/util/LASTCHANGE'], + 'action': ['python3', 'build/util/lastchange.py', + '-o', 'build/util/LASTCHANGE'], }, ]
diff --git a/DIR_METADATA b/DIR_METADATA new file mode 100644 index 0000000..507a6ca --- /dev/null +++ b/DIR_METADATA
@@ -0,0 +1,3 @@ +monorail { + component: "Internals>Plugins>PDF" +}
diff --git a/LICENSE b/LICENSE index bb158cb..161ca16 100644 --- a/LICENSE +++ b/LICENSE
@@ -1,4 +1,4 @@ -// Copyright 2014 PDFium Authors. All rights reserved. +// Copyright 2014 The PDFium Authors // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are
diff --git a/METADATA b/METADATA deleted file mode 100644 index 4eaf791..0000000 --- a/METADATA +++ /dev/null
@@ -1,9 +0,0 @@ -# *** THIS PACKAGE HAS SPECIAL LICENSING CONDITIONS. PLEASE -# CONSULT THE OWNERS AND opensource-licensing@google.com BEFORE -# DEPENDING ON IT IN YOUR PROJECT. *** -third_party { - license_note: "would be NOTICE save for OFL 1.1 in:\n" - " testing/resources/pixel/bug_925736.pdf\n" - " testing/resources/text_font.pdf" - license_type: BY_EXCEPTION_ONLY -}
diff --git a/PRESUBMIT.py b/PRESUBMIT.py index 9ad4abe..236f896 100644 --- a/PRESUBMIT.py +++ b/PRESUBMIT.py
@@ -1,4 +1,4 @@ -# Copyright 2015 The Chromium Authors. All rights reserved. +# Copyright 2015 The PDFium Authors # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. @@ -8,6 +8,10 @@ for more details about the presubmit API built into depot_tools. """ +PRESUBMIT_VERSION = '2.0.0' + +USE_PYTHON3 = True + LINT_FILTERS = [ # Rvalue ref checks are unreliable. '-build/c++11', @@ -34,6 +38,115 @@ 'cppguide.html#Names_and_Order_of_Includes') +# Bypass the AUTHORS check for these accounts. +_KNOWN_ROBOTS = set() | set( + '%s@skia-public.iam.gserviceaccount.com' % s for s in ('pdfium-autoroll',)) + +_THIRD_PARTY = 'third_party/' + +# Format: Sequence of tuples containing: +# * String pattern or, if starting with a slash, a regular expression. +# * Sequence of strings to show when the pattern matches. +# * Error flag. True if a match is a presubmit error, otherwise it's a warning. +# * Sequence of paths to *not* check (regexps). +_BANNED_CPP_FUNCTIONS = ( + ( + r'/\busing namespace ', + ( + 'Using directives ("using namespace x") are banned by the Google', + 'Style Guide (', + 'https://google.github.io/styleguide/cppguide.html#Namespaces ).', + 'Explicitly qualify symbols or use using declarations ("using', + 'x::foo").', + ), + True, + [_THIRD_PARTY], + ), + ( + r'/v8::Isolate::(?:|Try)GetCurrent()', + ( + 'v8::Isolate::GetCurrent() and v8::Isolate::TryGetCurrent() are', + 'banned. Hold a pointer to the v8::Isolate that was entered. Use', + 'v8::Isolate::IsCurrent() to check whether a given v8::Isolate is', + 'entered.', + ), + True, + (), + ), +) + + +def _CheckNoBannedFunctions(input_api, output_api): + """Makes sure that banned functions are not used.""" + warnings = [] + errors = [] + + def _GetMessageForMatchingType(input_api, affected_file, line_number, line, + type_name, message): + """Returns an string composed of the name of the file, the line number where + the match has been found and the additional text passed as `message` in case + the target type name matches the text inside the line passed as parameter. + """ + result = [] + + if input_api.re.search(r"^ *//", + line): # Ignore comments about banned types. + return result + if line.endswith( + " nocheck"): # A // nocheck comment will bypass this error. + return result + + matched = False + if type_name[0:1] == '/': + regex = type_name[1:] + if input_api.re.search(regex, line): + matched = True + elif type_name in line: + matched = True + + if matched: + result.append(' %s:%d:' % (affected_file.LocalPath(), line_number)) + for message_line in message: + result.append(' %s' % message_line) + + return result + + def IsExcludedFile(affected_file, excluded_paths): + local_path = affected_file.LocalPath() + for item in excluded_paths: + if input_api.re.match(item, local_path): + return True + return False + + def CheckForMatch(affected_file, line_num, line, func_name, message, error): + problems = _GetMessageForMatchingType(input_api, f, line_num, line, + func_name, message) + if problems: + if error: + errors.extend(problems) + else: + warnings.extend(problems) + + file_filter = lambda f: f.LocalPath().endswith(('.cc', '.cpp', '.h')) + for f in input_api.AffectedFiles(file_filter=file_filter): + for line_num, line in f.ChangedContents(): + for func_name, message, error, excluded_paths in _BANNED_CPP_FUNCTIONS: + if IsExcludedFile(f, excluded_paths): + continue + CheckForMatch(f, line_num, line, func_name, message, error) + + result = [] + if (warnings): + result.append( + output_api.PresubmitPromptWarning('Banned functions were used.\n' + + '\n'.join(warnings))) + if (errors): + result.append( + output_api.PresubmitError('Banned functions were used.\n' + + '\n'.join(errors))) + return result + + def _CheckUnwantedDependencies(input_api, output_api): """Runs checkdeps on #include statements added in this change. Breaking - rules is an error, breaking ! rules is a @@ -246,12 +359,8 @@ Each region separated by #if, #elif, #else, #endif, #define and #undef follows these rules separately. """ - def FileFilterIncludeOrder(affected_file): - black_list = (input_api.DEFAULT_BLACK_LIST) - return input_api.FilterSourceFile(affected_file, black_list=black_list) - warnings = [] - for f in input_api.AffectedFiles(file_filter=FileFilterIncludeOrder): + for f in input_api.AffectedFiles(file_filter=input_api.FilterSourceFile): if f.LocalPath().endswith(('.cc', '.cpp', '.h', '.mm')): changed_linenums = set(line_num for line_num, _ in f.ChangedContents()) warnings.extend(_CheckIncludeOrderInFile(input_api, f, changed_linenums)) @@ -262,6 +371,29 @@ warnings)) return results + +def _CheckLibcxxRevision(input_api, output_api): + """Makes sure that libcxx_revision is set correctly.""" + if 'DEPS' not in [f.LocalPath() for f in input_api.AffectedFiles()]: + return [] + + script_path = input_api.os_path.join('testing', 'tools', 'libcxx_check.py') + buildtools_deps_path = input_api.os_path.join('buildtools', + 'deps_revisions.gni') + + try: + errors = input_api.subprocess.check_output( + [script_path, 'DEPS', buildtools_deps_path]) + except input_api.subprocess.CalledProcessError as error: + msg = 'libcxx_check.py failed:' + long_text = error.output.decode('utf-8', 'ignore') + return [output_api.PresubmitError(msg, long_text=long_text)] + + if errors: + return [output_api.PresubmitError(errors)] + return [] + + def _CheckTestDuplicates(input_api, output_api): """Checks that pixel and javascript tests don't contain duplicates. We use .in and .pdf files, having both can cause race conditions on the bots, @@ -291,33 +423,136 @@ tests_added.append(path) return results -def _CheckPNGFormat(input_api, output_api): - """Checks that .png files have a format that will be considered valid by our - test runners. If a file ends with .png, then it must be of the form - NAME_expected(_(win|mac|linux))?.pdf.#.png""" + +def _CheckPngNames(input_api, output_api): + """Checks that .png files have the right file name format, which must be in + the form: + + NAME_expected(_(agg|skia))?(_(linux|mac|win))?.pdf.\d+.png + + This must be the same format as the one in testing/corpus's PRESUBMIT.py. + """ expected_pattern = input_api.re.compile( - r'.+_expected(_(win|mac|linux))?\.pdf\.\d+.png') + r'.+_expected(_(agg|skia))?(_(linux|mac|win))?\.pdf\.\d+.png') results = [] for f in input_api.AffectedFiles(include_deletes=False): if not f.LocalPath().endswith('.png'): continue if expected_pattern.match(f.LocalPath()): continue - results.append(output_api.PresubmitError( - 'PNG file %s does not have the correct format' % f.LocalPath())) + results.append( + output_api.PresubmitError( + 'PNG file %s does not have the correct format' % f.LocalPath())) return results -def CheckChangeOnUpload(input_api, output_api): - cpp_source_filter = lambda x: input_api.FilterSourceFile( - x, white_list=(r'\.(?:c|cc|cpp|h)$',)) +def _CheckUselessForwardDeclarations(input_api, output_api): + """Checks that added or removed lines in non third party affected + header files do not lead to new useless class or struct forward + declaration. + """ results = [] - results += _CheckUnwantedDependencies(input_api, output_api) - results += input_api.canned_checks.CheckPatchFormatted(input_api, output_api) - results += input_api.canned_checks.CheckChangeLintsClean( - input_api, output_api, cpp_source_filter, LINT_FILTERS) - results += _CheckIncludeOrder(input_api, output_api) - results += _CheckTestDuplicates(input_api, output_api) - results += _CheckPNGFormat(input_api, output_api) + class_pattern = input_api.re.compile(r'^class\s+(\w+);$', + input_api.re.MULTILINE) + struct_pattern = input_api.re.compile(r'^struct\s+(\w+);$', + input_api.re.MULTILINE) + for f in input_api.AffectedFiles(include_deletes=False): + if f.LocalPath().startswith('third_party'): + continue + + if not f.LocalPath().endswith('.h'): + continue + + contents = input_api.ReadFile(f) + fwd_decls = input_api.re.findall(class_pattern, contents) + fwd_decls.extend(input_api.re.findall(struct_pattern, contents)) + + useless_fwd_decls = [] + for decl in fwd_decls: + count = sum( + 1 + for _ in input_api.re.finditer(r'\b%s\b' % + input_api.re.escape(decl), contents)) + if count == 1: + useless_fwd_decls.append(decl) + + if not useless_fwd_decls: + continue + + for line in f.GenerateScmDiff().splitlines(): + if (line.startswith('-') and not line.startswith('--') or + line.startswith('+') and not line.startswith('++')): + for decl in useless_fwd_decls: + if input_api.re.search(r'\b%s\b' % decl, line[1:]): + results.append( + output_api.PresubmitPromptWarning( + '%s: %s forward declaration is no longer needed' % + (f.LocalPath(), decl))) + useless_fwd_decls.remove(decl) + + return results + + +def ChecksCommon(input_api, output_api): + results = [] + + results.extend( + input_api.canned_checks.PanProjectChecks( + input_api, output_api, project_name='PDFium')) + + # PanProjectChecks() doesn't consider .gn/.gni files, so check those, too. + files_to_check = ( + r'.*\.gn$', + r'.*\.gni$', + ) + results.extend( + input_api.canned_checks.CheckLicense( + input_api, + output_api, + project_name='PDFium', + source_file_filter=lambda x: input_api.FilterSourceFile( + x, files_to_check=files_to_check))) + + return results + + +def CheckChangeOnUpload(input_api, output_api): + results = [] + results.extend(_CheckNoBannedFunctions(input_api, output_api)) + results.extend(_CheckUnwantedDependencies(input_api, output_api)) + results.extend( + input_api.canned_checks.CheckPatchFormatted(input_api, output_api)) + results.extend( + input_api.canned_checks.CheckChangeLintsClean( + input_api, output_api, lint_filters=LINT_FILTERS)) + results.extend(_CheckIncludeOrder(input_api, output_api)) + results.extend(_CheckLibcxxRevision(input_api, output_api)) + results.extend(_CheckTestDuplicates(input_api, output_api)) + results.extend(_CheckPngNames(input_api, output_api)) + results.extend(_CheckUselessForwardDeclarations(input_api, output_api)) + + author = input_api.change.author_email + if author and author not in _KNOWN_ROBOTS: + results.extend( + input_api.canned_checks.CheckAuthorizedAuthor(input_api, output_api)) + + for f in input_api.AffectedFiles(): + path, name = input_api.os_path.split(f.LocalPath()) + if name == 'PRESUBMIT.py': + full_path = input_api.os_path.join(input_api.PresubmitLocalPath(), path) + test_file = input_api.os_path.join(path, 'PRESUBMIT_test.py') + if f.Action() != 'D' and input_api.os_path.exists(test_file): + # The PRESUBMIT.py file (and the directory containing it) might + # have been affected by being moved or removed, so only try to + # run the tests if they still exist. + results.extend( + input_api.canned_checks.RunUnitTestsInDirectory( + input_api, + output_api, + full_path, + files_to_check=[r'^PRESUBMIT_test\.py$'], + run_on_python2=not USE_PYTHON3, + run_on_python3=USE_PYTHON3, + skip_shebang_check=True)) return results
diff --git a/PRESUBMIT_test.py b/PRESUBMIT_test.py new file mode 100755 index 0000000..c5f9650 --- /dev/null +++ b/PRESUBMIT_test.py
@@ -0,0 +1,86 @@ +#!/usr/bin/env python3 +# Copyright 2020 The PDFium Authors +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +import unittest + +import PRESUBMIT +from PRESUBMIT_test_mocks import MockInputApi, MockOutputApi, MockFile + + +class BannedTypeCheckTest(unittest.TestCase): + + def testBannedCppFunctions(self): + input_api = MockInputApi() + input_api.files = [ + MockFile('some/cpp/problematic/file.cc', ['using namespace std;']), + MockFile('third_party/some/cpp/problematic/file.cc', + ['using namespace std;']), + MockFile('some/cpp/ok/file.cc', ['using std::string;']), + MockFile('some/cpp/nocheck/file.cc', + ['using namespace std; // nocheck']), + MockFile('some/cpp/comment/file.cc', + [' // A comment about `using namespace std;`']), + MockFile('some/cpp/v8/get-current.cc', ['v8::Isolate::GetCurrent()']), + MockFile('some/cpp/v8/try-get-current.cc', + ['v8::Isolate::TryGetCurrent()']), + ] + + results = PRESUBMIT._CheckNoBannedFunctions(input_api, MockOutputApi()) + + # There are no warnings to test, so add an empty warning to keep the test + # extendable for the future. This block can be removed once warnings are + # added. + self.assertEqual(1, len(results)) + results.insert(0, MockOutputApi().PresubmitPromptWarning('')) + + # warnings are results[0], errors are results[1] + self.assertEqual(2, len(results)) + self.assertTrue('some/cpp/problematic/file.cc' in results[1].message) + self.assertFalse( + 'third_party/some/cpp/problematic/file.cc' in results[1].message) + self.assertFalse('some/cpp/ok/file.cc' in results[1].message) + self.assertFalse('some/cpp/nocheck/file.cc' in results[0].message) + self.assertFalse('some/cpp/nocheck/file.cc' in results[1].message) + self.assertFalse('some/cpp/comment/file.cc' in results[0].message) + self.assertFalse('some/cpp/comment/file.cc' in results[1].message) + self.assertTrue('some/cpp/v8/get-current.cc' in results[1].message) + self.assertTrue('some/cpp/v8/try-get-current.cc' in results[1].message) + + +class CheckChangeOnUploadTest(unittest.TestCase): + + def testCheckPngNames(self): + correct_paths = [ + 'test_expected.pdf.0.png', + 'test_expected_win.pdf.1.png', + 'test_expected_agg.pdf.3.png', + 'test_expected_agg_linux.pdf.3.png', + 'test_expected_skia.pdf.2.png', + 'test_expected_skia_mac.pdf.4.png', + 'notpng.cc', # Check will be skipped for non-PNG files + ] + wrong_paths = [ + 'expected.pdf.0.png', # Missing '_expected' + 'test1_expected.0.png', # Missing '.pdf' + 'test2_expected.pdf.png', # Missing page number + 'test3_expected.pdf.x.png', # Wrong character for page number + 'test4_expected_linux_agg.pdf.0.png', # Wrong order of keywords + 'test4_expected_mac_skia.pdf.0.png', # Wrong order of keywords + 'test5_expected_useskia.pdf.0.png', # Wrong keyword + ] + mock_input_api = MockInputApi() + mock_output_api = MockOutputApi() + mock_input_api.files = map(MockFile, correct_paths + wrong_paths) + errors = list( + map(str, PRESUBMIT._CheckPngNames(mock_input_api, mock_output_api))) + + self.assertEqual(len(wrong_paths), len(errors)) + self.assertFalse('notpng.cc' in errors[0]) + for path, error in zip(wrong_paths, errors): + self.assertIn(path, error) + + +if __name__ == '__main__': + unittest.main()
diff --git a/PRESUBMIT_test_mocks.py b/PRESUBMIT_test_mocks.py new file mode 100644 index 0000000..23e3946 --- /dev/null +++ b/PRESUBMIT_test_mocks.py
@@ -0,0 +1,78 @@ +# Copyright 2020 The PDFium Authors +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +import re + + +class MockInputApi(object): + """Mock class for the InputApi class. + + This class can be used for unittests for presubmit by initializing the files + attribute as the list of changed files. + """ + + def __init__(self): + self.files = [] + self.re = re + + def AffectedFiles(self, file_filter=None, include_deletes=False): + # pylint: disable=unused-argument + return self.files + + +class MockOutputApi(object): + """Mock class for the OutputApi class. + + An instance of this class can be passed to presubmit unittests for outputting + various types of results. + """ + + class PresubmitResult(object): + + def __init__(self, message, items=None, long_text=''): + self.message = message + self.items = items + self.long_text = long_text + + def __repr__(self): + return self.message + + class PresubmitError(PresubmitResult): + + def __init__(self, message, items=None, long_text=''): + MockOutputApi.PresubmitResult.__init__(self, message, items, long_text) + self.type = 'error' + + class PresubmitPromptWarning(PresubmitResult): + + def __init__(self, message, items=None, long_text=''): + MockOutputApi.PresubmitResult.__init__(self, message, items, long_text) + self.type = 'warning' + + +class MockFile(object): + """Mock class for the File class. + + This class can be used to form the mock list of changed files in + MockInputApi for presubmit unittests. + """ + + def __init__(self, + local_path, + new_contents=None, + old_contents=None, + action='A'): + self._local_path = local_path + if new_contents is None: + new_contents = [] + self._new_contents = new_contents + self._changed_contents = [(i + 1, l) for i, l in enumerate(new_contents)] + self._action = action + self._old_contents = old_contents + + def ChangedContents(self): + return self._changed_contents + + def LocalPath(self): + return self._local_path
diff --git a/README.md b/README.md index a79e18d..657cfda 100644 --- a/README.md +++ b/README.md
@@ -2,27 +2,13 @@ ## Prerequisites -Get the Chromium depot\_tools via the -[instructions](https://www.chromium.org/developers/how-tos/install-depot-tools). -This provides the gclient utility needed below and many other tools needed for -PDFium development. +PDFium uses the same build tooling as Chromium. See the platform-specific +Chromium build instructions to get started, but replace Chromium's +"Get the code" instructions with [PDFium's](#get-the-code). -Also install Python, Subversion, and Git and make sure they're in your path. - - -### Windows development - -PDFium uses the same build tool as Chromium: - -#### Open source contributors -Please refer to -[Chromium's Visual Studio set up](https://chromium.googlesource.com/chromium/src/+/master/docs/windows_build_instructions.md#visual-studio) -for requirements and instructions on build environment configuration. - -Run `set DEPOT_TOOLS_WIN_TOOLCHAIN=0`, or set that variable in your global -environment. - -Compilation is done through Ninja, **not** Visual Studio. +* [Chromium Linux build instructions](https://chromium.googlesource.com/chromium/src/+/main/docs/linux/build_instructions.md) +* [Chromium Mac build instructions](https://chromium.googlesource.com/chromium/src/+/main/docs/mac_build_instructions.md) +* [Chromium Windows build instructions](https://chromium.googlesource.com/chromium/src/+/main/docs/windows_build_instructions.md) ### CPU Architectures supported @@ -42,7 +28,7 @@ @google.com credentials**. Enter "0" if asked for a project-id. Once you've done this, the toolchain will be installed automatically for -you in the [Generate the build files](#GenBuild) step below. +you in the [Generate the build files](#generate-the-build-files) step below. The toolchain will be in `depot_tools\win_toolchain\vs_files\<hash>`, and windbg can be found in @@ -53,9 +39,10 @@ ## Get the code -The name of the top-level directory does not matter. In our examples, we use -"repo". This directory must not have been used before by `gclient config` as -each directory can only house a single gclient configuration. +The name of the top-level directory does not matter. In the following example, +the directory name is "repo". This directory must not have been used before by +`gclient config` as each directory can only house a single gclient +configuration. ``` mkdir repo @@ -65,8 +52,8 @@ cd pdfium ``` -Additional build dependencies need to be installed by running the following from -the `pdfium` directory. +On Linux, additional build dependencies need to be installed by running the +following from the `pdfium` directory. ``` ./build/install-build-deps.sh @@ -74,7 +61,7 @@ ## Generate the build files -We use GN to generate the build files and [Ninja](https://ninja-build.org/) +PDFium uses GN to generate the build files and [Ninja](https://ninja-build.org/) to execute the build files. Both of these are included with the depot\_tools checkout. @@ -96,30 +83,17 @@ # Set true to enable experimental Skia backend. pdf_use_skia = false -# Set true to enable experimental Skia backend (paths only). -pdf_use_skia_paths = false pdf_enable_xfa = true # Set false to remove XFA support (implies JS support). pdf_enable_v8 = true # Set false to remove Javascript support. pdf_is_standalone = true # Set for a non-embedded build. is_component_build = false # Disable component build (Though it should work) - -clang_use_chrome_plugins = false # Currently must be false. ``` For sample applications like `pdfium_test` to build, one must set `pdf_is_standalone = true`. -By default, the entire project builds with C++14, because features like V8 -support, XFA support, and the Skia backend all have dependencies on libraries -that require C++14. If one does not need any of those features, and need to fall -back to building in C++11 mode, then set `use_cxx11 = true`. This fallback is -temporary and will go away in the future when PDFium fully transitions to C++14. -See [this bug](https://crbug.com/pdfium/1407) for details. - -When building with the experimental Skia backend, Skia itself it built with -C++17. There is no configuration for this. One just has to use a build toolchain -that supports C++17. +By default, the entire project builds with C++17. When complete the arguments will be stored in `<directory>/args.gn`, and GN will automatically use the new arguments to generate build files. @@ -190,7 +164,7 @@ This saves space and also allows an easy way to reduce the test case to the essentials as you can simply remove everything that is not necessary. -A simple example can be found [here](https://pdfium.googlesource.com/pdfium/+/refs/heads/master/testing/resources/rectangles.in). +A simple example can be found [here](https://pdfium.googlesource.com/pdfium/+/refs/heads/main/testing/resources/rectangles.in). To transform this into a PDF, you can use the `fixup_pdf_template.py` tool: @@ -208,7 +182,8 @@ ## Embedding PDFium in your own projects The public/ directory contains header files for the APIs available for use by -embedders of PDFium. We endeavor to keep these as stable as possible. +embedders of PDFium. The PDFium project endeavors to keep these as stable as +possible. Outside of the public/ directory, code may change at any time, and embedders should not directly call these routines. @@ -223,13 +198,6 @@ `third_party/pdfium` in Chromium's source code. This includes code coverage from PDFium's fuzzers. -## Profiling - -Valgrind and other profiling tools do not work correctly with the standard build -setup that PDFium uses. You will need to add -`ro_segment_workaround_for_valgrind=true` to `args.gn` to get symbols to -correctly appear. - ## Waterfall The current health of the source tree can be found @@ -247,26 +215,12 @@ ## Bugs - We use this -[bug tracker](https://bugs.chromium.org/p/pdfium/issues/list), but for security -bugs, please use +PDFium uses this [bug tracker](https://bugs.chromium.org/p/pdfium/issues/list), +but for security bugs, please use [Chromium's security bug template](https://bugs.chromium.org/p/chromium/issues/entry?template=Security%20Bug) and add the "Cr-Internals-Plugins-PDF" label. ## Contributing code -For contributing code, we will follow -[Chromium's process](https://chromium.googlesource.com/chromium/src/+/master/docs/contributing.md) -as much as possible. The main exceptions are: - -1. Code has to conform to the existing style and not Chromium/Google style. -2. PDFium uses a different Gerrit instance for code reviews, and credentials for -this Gerrit instance need to be generated before uploading changes. -3. PDFium is transitioning to C++14, but still supports C++11 compatibility -for the duration of the transition period. Prefer to use only C++11 features, -though technically C++14 is allowed in code that is only built when V8, XFA, or -Skia is turned on. - -Before submitting a fix for a bug, it can help if you create an issue in the -bug tracker. This allows easier discussion about the problem and also helps -with statistics tracking. +See the [CONTRIBUTING](CONTRIBUTING.md) document for more information on +contributing to the PDFium project.
diff --git a/build/build_config.h b/build/build_config.h index 8165eee..478c4cf 100644 --- a/build/build_config.h +++ b/build/build_config.h
@@ -1,7 +1,390 @@ -#define OS_POSIX -#define OS_ANDROID +// Copyright 2012 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// This file doesn't belong to any GN target by design for faster build and +// less developer overhead. + +// This file adds build flags about the OS we're currently building on. They are +// defined directly in this file instead of via a `buildflag_header` target in a +// GN file for faster build. They are defined using the corresponding OS defines +// (e.g. OS_WIN) which are also defined in this file (except for OS_CHROMEOS, +// which is set by the build system). These defines are deprecated and should +// NOT be used directly. For example: +// Please Use: #if BUILDFLAG(IS_WIN) +// Deprecated: #if defined(OS_WIN) +// +// Operating System: +// IS_AIX / IS_ANDROID / IS_ASMJS / IS_CHROMEOS / IS_FREEBSD / IS_FUCHSIA / +// IS_IOS / IS_IOS_MACCATALYST / IS_LINUX / IS_MAC / IS_NACL / IS_NETBSD / +// IS_OPENBSD / IS_QNX / IS_SOLARIS / IS_WIN +// Operating System family: +// IS_APPLE: IOS or MAC or IOS_MACCATALYST +// IS_BSD: FREEBSD or NETBSD or OPENBSD +// IS_POSIX: AIX or ANDROID or ASMJS or CHROMEOS or FREEBSD or IOS or LINUX +// or MAC or NACL or NETBSD or OPENBSD or QNX or SOLARIS + +// This file also adds defines specific to the platform, architecture etc. +// +// Platform: +// IS_OZONE +// +// Compiler: +// COMPILER_MSVC / COMPILER_GCC +// +// Processor: +// ARCH_CPU_ARM64 / ARCH_CPU_ARMEL / ARCH_CPU_LOONGARCH32 / +// ARCH_CPU_LOONGARCH64 / ARCH_CPU_MIPS / ARCH_CPU_MIPS64 / +// ARCH_CPU_MIPS64EL / ARCH_CPU_MIPSEL / ARCH_CPU_PPC64 / ARCH_CPU_S390 / +// ARCH_CPU_S390X / ARCH_CPU_X86 / ARCH_CPU_X86_64 / ARCH_CPU_RISCV64 +// Processor family: +// ARCH_CPU_ARM_FAMILY: ARMEL or ARM64 +// ARCH_CPU_LOONGARCH_FAMILY: LOONGARCH32 or LOONGARCH64 +// ARCH_CPU_MIPS_FAMILY: MIPS64EL or MIPSEL or MIPS64 or MIPS +// ARCH_CPU_PPC64_FAMILY: PPC64 +// ARCH_CPU_S390_FAMILY: S390 or S390X +// ARCH_CPU_X86_FAMILY: X86 or X86_64 +// ARCH_CPU_RISCV_FAMILY: Riscv64 +// Processor features: +// ARCH_CPU_31_BITS / ARCH_CPU_32_BITS / ARCH_CPU_64_BITS +// ARCH_CPU_BIG_ENDIAN / ARCH_CPU_LITTLE_ENDIAN + +#ifndef BUILD_BUILD_CONFIG_H_ +#define BUILD_BUILD_CONFIG_H_ + +#include "build/buildflag.h" // IWYU pragma: export + +// A set of macros to use for platform detection. +#if defined(__native_client__) +// __native_client__ must be first, so that other OS_ defines are not set. +#define OS_NACL 1 +#elif defined(ANDROID) +#define OS_ANDROID 1 +#elif defined(__APPLE__) +// Only include TargetConditionals after testing ANDROID as some Android builds +// on the Mac have this header available and it's not needed unless the target +// is really an Apple platform. +#include <TargetConditionals.h> +#if defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE +#define OS_IOS 1 +// Catalyst is the technology that allows running iOS apps on macOS. These +// builds are both OS_IOS and OS_IOS_MACCATALYST. +#if defined(TARGET_OS_MACCATALYST) && TARGET_OS_MACCATALYST +#define OS_IOS_MACCATALYST +#endif // defined(TARGET_OS_MACCATALYST) && TARGET_OS_MACCATALYST +#else +#define OS_MAC 1 +#endif // defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE +#elif defined(__linux__) +#if !defined(OS_CHROMEOS) +// Do not define OS_LINUX on Chrome OS build. +// The OS_CHROMEOS macro is defined in GN. +#define OS_LINUX 1 +#endif // !defined(OS_CHROMEOS) +// Include a system header to pull in features.h for glibc/uclibc macros. +#include <assert.h> +#if defined(__GLIBC__) && !defined(__UCLIBC__) +// We really are using glibc, not uClibc pretending to be glibc. +#define LIBC_GLIBC 1 +#endif +#elif defined(_WIN32) +#define OS_WIN 1 +#elif defined(__Fuchsia__) +#define OS_FUCHSIA 1 +#elif defined(__FreeBSD__) +#define OS_FREEBSD 1 +#elif defined(__NetBSD__) +#define OS_NETBSD 1 +#elif defined(__OpenBSD__) +#define OS_OPENBSD 1 +#elif defined(__sun) +#define OS_SOLARIS 1 +#elif defined(__QNXNTO__) +#define OS_QNX 1 +#elif defined(_AIX) +#define OS_AIX 1 +#elif defined(__asmjs__) || defined(__wasm__) +#define OS_ASMJS 1 +#elif defined(__MVS__) +#define OS_ZOS 1 +#else +#error Please add support for your platform in build/build_config.h +#endif +// NOTE: Adding a new port? Please follow +// https://chromium.googlesource.com/chromium/src/+/main/docs/new_port_policy.md + +#if defined(OS_MAC) || defined(OS_IOS) +#define OS_APPLE 1 +#endif + +// For access to standard BSD features, use OS_BSD instead of a +// more specific macro. +#if defined(OS_FREEBSD) || defined(OS_NETBSD) || defined(OS_OPENBSD) +#define OS_BSD 1 +#endif + +// For access to standard POSIXish features, use OS_POSIX instead of a +// more specific macro. +#if defined(OS_AIX) || defined(OS_ANDROID) || defined(OS_ASMJS) || \ + defined(OS_FREEBSD) || defined(OS_IOS) || defined(OS_LINUX) || \ + defined(OS_CHROMEOS) || defined(OS_MAC) || defined(OS_NACL) || \ + defined(OS_NETBSD) || defined(OS_OPENBSD) || defined(OS_QNX) || \ + defined(OS_SOLARIS) || defined(OS_ZOS) +#define OS_POSIX 1 +#endif + +// OS build flags +#if defined(OS_AIX) +#define BUILDFLAG_INTERNAL_IS_AIX() (1) +#else +#define BUILDFLAG_INTERNAL_IS_AIX() (0) +#endif + +#if defined(OS_ANDROID) +#define BUILDFLAG_INTERNAL_IS_ANDROID() (1) +#else +#define BUILDFLAG_INTERNAL_IS_ANDROID() (0) +#endif + +#if defined(OS_APPLE) +#define BUILDFLAG_INTERNAL_IS_APPLE() (1) +#else +#define BUILDFLAG_INTERNAL_IS_APPLE() (0) +#endif + +#if defined(OS_ASMJS) +#define BUILDFLAG_INTERNAL_IS_ASMJS() (1) +#else +#define BUILDFLAG_INTERNAL_IS_ASMJS() (0) +#endif + +#if defined(OS_BSD) +#define BUILDFLAG_INTERNAL_IS_BSD() (1) +#else +#define BUILDFLAG_INTERNAL_IS_BSD() (0) +#endif + +#if defined(OS_CHROMEOS) +#define BUILDFLAG_INTERNAL_IS_CHROMEOS() (1) +#else +#define BUILDFLAG_INTERNAL_IS_CHROMEOS() (0) +#endif + +#if defined(OS_FREEBSD) +#define BUILDFLAG_INTERNAL_IS_FREEBSD() (1) +#else +#define BUILDFLAG_INTERNAL_IS_FREEBSD() (0) +#endif + +#if defined(OS_FUCHSIA) +#define BUILDFLAG_INTERNAL_IS_FUCHSIA() (1) +#else +#define BUILDFLAG_INTERNAL_IS_FUCHSIA() (0) +#endif + +#if defined(OS_IOS) +#define BUILDFLAG_INTERNAL_IS_IOS() (1) +#else +#define BUILDFLAG_INTERNAL_IS_IOS() (0) +#endif + +#if defined(OS_IOS_MACCATALYST) +#define BUILDFLAG_INTERNAL_IS_IOS_MACCATALYST() (1) +#else +#define BUILDFLAG_INTERNAL_IS_IOS_MACCATALYST() (0) +#endif + +#if defined(OS_LINUX) +#define BUILDFLAG_INTERNAL_IS_LINUX() (1) +#else +#define BUILDFLAG_INTERNAL_IS_LINUX() (0) +#endif + +#if defined(OS_MAC) +#define BUILDFLAG_INTERNAL_IS_MAC() (1) +#else +#define BUILDFLAG_INTERNAL_IS_MAC() (0) +#endif + +#if defined(OS_NACL) +#define BUILDFLAG_INTERNAL_IS_NACL() (1) +#else +#define BUILDFLAG_INTERNAL_IS_NACL() (0) +#endif + +#if defined(OS_NETBSD) +#define BUILDFLAG_INTERNAL_IS_NETBSD() (1) +#else +#define BUILDFLAG_INTERNAL_IS_NETBSD() (0) +#endif + +#if defined(OS_OPENBSD) +#define BUILDFLAG_INTERNAL_IS_OPENBSD() (1) +#else +#define BUILDFLAG_INTERNAL_IS_OPENBSD() (0) +#endif + +#if defined(OS_POSIX) +#define BUILDFLAG_INTERNAL_IS_POSIX() (1) +#else +#define BUILDFLAG_INTERNAL_IS_POSIX() (0) +#endif + +#if defined(OS_QNX) +#define BUILDFLAG_INTERNAL_IS_QNX() (1) +#else +#define BUILDFLAG_INTERNAL_IS_QNX() (0) +#endif + +#if defined(OS_SOLARIS) +#define BUILDFLAG_INTERNAL_IS_SOLARIS() (1) +#else +#define BUILDFLAG_INTERNAL_IS_SOLARIS() (0) +#endif + +#if defined(OS_WIN) +#define BUILDFLAG_INTERNAL_IS_WIN() (1) +#else +#define BUILDFLAG_INTERNAL_IS_WIN() (0) +#endif + +#if defined(USE_OZONE) +#define BUILDFLAG_INTERNAL_IS_OZONE() (1) +#else +#define BUILDFLAG_INTERNAL_IS_OZONE() (0) +#endif + +// Compiler detection. Note: clang masquerades as GCC on POSIX and as MSVC on +// Windows. +#if defined(__GNUC__) +#define COMPILER_GCC 1 +#elif defined(_MSC_VER) +#define COMPILER_MSVC 1 +#else +#error Please add support for your compiler in build/build_config.h +#endif + +// Processor architecture detection. For more info on what's defined, see: +// http://msdn.microsoft.com/en-us/library/b0084kay.aspx +// http://www.agner.org/optimize/calling_conventions.pdf +// or with gcc, run: "echo | gcc -E -dM -" +#if defined(_M_X64) || defined(__x86_64__) +#define ARCH_CPU_X86_FAMILY 1 +#define ARCH_CPU_X86_64 1 +#define ARCH_CPU_64_BITS 1 +#define ARCH_CPU_LITTLE_ENDIAN 1 +#elif defined(_M_IX86) || defined(__i386__) +#define ARCH_CPU_X86_FAMILY 1 +#define ARCH_CPU_X86 1 +#define ARCH_CPU_32_BITS 1 +#define ARCH_CPU_LITTLE_ENDIAN 1 +#elif defined(__s390x__) +#define ARCH_CPU_S390_FAMILY 1 +#define ARCH_CPU_S390X 1 +#define ARCH_CPU_64_BITS 1 +#define ARCH_CPU_BIG_ENDIAN 1 +#elif defined(__s390__) +#define ARCH_CPU_S390_FAMILY 1 +#define ARCH_CPU_S390 1 +#define ARCH_CPU_31_BITS 1 +#define ARCH_CPU_BIG_ENDIAN 1 +#elif (defined(__PPC64__) || defined(__PPC__)) && defined(__BIG_ENDIAN__) +#define ARCH_CPU_PPC64_FAMILY 1 +#define ARCH_CPU_PPC64 1 +#define ARCH_CPU_64_BITS 1 +#define ARCH_CPU_BIG_ENDIAN 1 +#elif defined(__PPC64__) +#define ARCH_CPU_PPC64_FAMILY 1 +#define ARCH_CPU_PPC64 1 +#define ARCH_CPU_64_BITS 1 +#define ARCH_CPU_LITTLE_ENDIAN 1 +#elif defined(__ARMEL__) +#define ARCH_CPU_ARM_FAMILY 1 +#define ARCH_CPU_ARMEL 1 +#define ARCH_CPU_32_BITS 1 +#define ARCH_CPU_LITTLE_ENDIAN 1 +#elif defined(__aarch64__) || defined(_M_ARM64) +#define ARCH_CPU_ARM_FAMILY 1 +#define ARCH_CPU_ARM64 1 +#define ARCH_CPU_64_BITS 1 +#define ARCH_CPU_LITTLE_ENDIAN 1 +#elif defined(__pnacl__) || defined(__asmjs__) || defined(__wasm__) +#define ARCH_CPU_32_BITS 1 +#define ARCH_CPU_LITTLE_ENDIAN 1 +#elif defined(__MIPSEL__) +#if defined(__LP64__) +#define ARCH_CPU_MIPS_FAMILY 1 +#define ARCH_CPU_MIPS64EL 1 +#define ARCH_CPU_64_BITS 1 +#define ARCH_CPU_LITTLE_ENDIAN 1 +#else +#define ARCH_CPU_MIPS_FAMILY 1 +#define ARCH_CPU_MIPSEL 1 +#define ARCH_CPU_32_BITS 1 +#define ARCH_CPU_LITTLE_ENDIAN 1 +#endif +#elif defined(__MIPSEB__) +#if defined(__LP64__) +#define ARCH_CPU_MIPS_FAMILY 1 +#define ARCH_CPU_MIPS64 1 +#define ARCH_CPU_64_BITS 1 +#define ARCH_CPU_BIG_ENDIAN 1 +#else +#define ARCH_CPU_MIPS_FAMILY 1 +#define ARCH_CPU_MIPS 1 +#define ARCH_CPU_32_BITS 1 +#define ARCH_CPU_BIG_ENDIAN 1 +#endif +#elif defined(__loongarch__) +#define ARCH_CPU_LOONGARCH_FAMILY 1 +#define ARCH_CPU_LITTLE_ENDIAN 1 +#if __loongarch_grlen == 64 +#define ARCH_CPU_LOONGARCH64 1 +#define ARCH_CPU_64_BITS 1 +#else +#define ARCH_CPU_LOONGARCH32 1 +#define ARCH_CPU_32_BITS 1 +#endif +#elif defined(__riscv) && (__riscv_xlen == 64) +#define ARCH_CPU_RISCV_FAMILY 1 +#define ARCH_CPU_RISCV64 1 +#define ARCH_CPU_64_BITS 1 +#define ARCH_CPU_LITTLE_ENDIAN 1 +#else +#error Please add support for your architecture in build/build_config.h +#endif + +// Type detection for wchar_t. +#if defined(OS_WIN) +#define WCHAR_T_IS_UTF16 +#elif defined(OS_FUCHSIA) +#define WCHAR_T_IS_UTF32 +#elif defined(OS_POSIX) && defined(COMPILER_GCC) && defined(__WCHAR_MAX__) && \ + (__WCHAR_MAX__ == 0x7fffffff || __WCHAR_MAX__ == 0xffffffff) +#define WCHAR_T_IS_UTF32 +#elif defined(OS_POSIX) && defined(COMPILER_GCC) && defined(__WCHAR_MAX__) && \ + (__WCHAR_MAX__ == 0x7fff || __WCHAR_MAX__ == 0xffff) +// On Posix, we'll detect short wchar_t, but projects aren't guaranteed to +// compile in this mode (in particular, Chrome doesn't). This is intended for +// other projects using base who manage their own dependencies and make sure +// short wchar works for them. +#define WCHAR_T_IS_UTF16 +#else +#error Please add support for your compiler in build/build_config.h +#endif + +#if defined(OS_ANDROID) +// The compiler thinks std::string::const_iterator and "const char*" are +// equivalent types. +#define STD_STRING_ITERATOR_IS_CHAR_POINTER +// The compiler thinks std::u16string::const_iterator and "char16*" are +// equivalent types. +#define BASE_STRING16_ITERATOR_IS_CHAR16_POINTER +#endif + #define USE_SYSTEM_ICUUC #define USE_SYSTEM_LIBJPEG #define USE_SYSTEM_ZLIB -// Makes base/logging.h and base/bits.h work. -#define COMPILER_GCC + +#endif // BUILD_BUILD_CONFIG_H_ +
diff --git a/build/buildflag.h b/build/buildflag.h new file mode 100644 index 0000000..d87a220 --- /dev/null +++ b/build/buildflag.h
@@ -0,0 +1,48 @@ +// Copyright 2015 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef BUILD_BUILDFLAG_H_ +#define BUILD_BUILDFLAG_H_ + +// These macros un-mangle the names of the build flags in a way that looks +// natural, and gives errors if the flag is not defined. Normally in the +// preprocessor it's easy to make mistakes that interpret "you haven't done +// the setup to know what the flag is" as "flag is off". Normally you would +// include the generated header rather than include this file directly. +// +// This is for use with generated headers. See build/buildflag_header.gni. + +// This dance of two macros does a concatenation of two preprocessor args using +// ## doubly indirectly because using ## directly prevents macros in that +// parameter from being expanded. +#define BUILDFLAG_CAT_INDIRECT(a, b) a ## b +#define BUILDFLAG_CAT(a, b) BUILDFLAG_CAT_INDIRECT(a, b) + +// Accessor for build flags. +// +// To test for a value, if the build file specifies: +// +// ENABLE_FOO=true +// +// Then you would check at build-time in source code with: +// +// #include "foo_flags.h" // The header the build file specified. +// +// #if BUILDFLAG(ENABLE_FOO) +// ... +// #endif +// +// There will no #define called ENABLE_FOO so if you accidentally test for +// whether that is defined, it will always be negative. You can also use +// the value in expressions: +// +// const char kSpamServerName[] = BUILDFLAG(SPAM_SERVER_NAME); +// +// Because the flag is accessed as a preprocessor macro with (), an error +// will be thrown if the proper header defining the internal flag value has +// not been included. +#define BUILDFLAG(flag) (BUILDFLAG_CAT(BUILDFLAG_INTERNAL_, flag)()) + +#endif // BUILD_BUILDFLAG_H_ +
diff --git a/build_overrides/BUILDCONFIG.gn b/build_overrides/BUILDCONFIG.gn new file mode 100644 index 0000000..2b9bbd6 --- /dev/null +++ b/build_overrides/BUILDCONFIG.gn
@@ -0,0 +1,627 @@ +# Copyright 2022 The PDFium Authors +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +# ============================================================================= +# WHAT IS THIS FILE? +# ============================================================================= +# +# This is a copy of //build/config/BUILDCONFIG.gn. The difference is it adds an +# extra default_compiler_configs to use PDFium's desired default compiler +# config. See "PDFIUM MODIFICATIONS" below. +# +# This is the main GN build configuration. This file is loaded after the +# build args (args.gn) for the build directory and after the toplevel ".gn" +# file (which points to this file as the build configuration). +# +# This file will be executed and the resulting context will be used to execute +# every other file in the build. So variables declared here (that don't start +# with an underscore) will be implicitly global. + +# ============================================================================= +# PLATFORM SELECTION +# ============================================================================= +# +# There are two main things to set: "os" and "cpu". The "toolchain" is the name +# of the GN thing that encodes combinations of these things. +# +# Users typically only set the variables "target_os" and "target_cpu" in "gn +# args", the rest are set up by our build and internal to GN. +# +# There are three different types of each of these things: The "host" +# represents the computer doing the compile and never changes. The "target" +# represents the main thing we're trying to build. The "current" represents +# which configuration is currently being defined, which can be either the +# host, the target, or something completely different (like nacl). GN will +# run the same build file multiple times for the different required +# configuration in the same build. +# +# This gives the following variables: +# - host_os, host_cpu, host_toolchain +# - target_os, target_cpu, default_toolchain +# - current_os, current_cpu, current_toolchain. +# +# Note the default_toolchain isn't symmetrical (you would expect +# target_toolchain). This is because the "default" toolchain is a GN built-in +# concept, and "target" is something our build sets up that's symmetrical with +# its GYP counterpart. Potentially the built-in default_toolchain variable +# could be renamed in the future. +# +# When writing build files, to do something only for the host: +# if (current_toolchain == host_toolchain) { ... + +if (target_os == "") { + target_os = host_os +} + +if (target_cpu == "") { + if (target_os == "android") { + # If we're building for Android, we should assume that we want to + # build for ARM by default, not the host_cpu (which is likely x64). + # This allows us to not have to specify both target_os and target_cpu + # on the command line. + target_cpu = "arm" + } else { + target_cpu = host_cpu + } +} + +if (current_cpu == "") { + current_cpu = target_cpu +} +if (current_os == "") { + current_os = target_os +} + +# ============================================================================= +# BUILD FLAGS +# ============================================================================= +# +# This block lists input arguments to the build, along with their default +# values. +# +# If a value is specified on the command line, it will overwrite the defaults +# given in a declare_args block, otherwise the default will be used. +# +# YOU SHOULD ALMOST NEVER NEED TO ADD FLAGS TO THIS FILE. GN allows any file in +# the build to declare build flags. If you need a flag for a single component, +# you can just declare it in the corresponding BUILD.gn file. +# +# - If your feature is a single target, say //components/foo, you can put +# a declare_args() block in //components/foo/BUILD.gn and use it there. +# Nobody else in the build needs to see the flag. +# +# - Defines based on build variables should be implemented via the generated +# build flag header system. See //build/buildflag_header.gni. You can put +# the buildflag_header target in the same file as the build flag itself. You +# should almost never set "defines" directly. +# +# - If your flag toggles a target on and off or toggles between different +# versions of similar things, write a "group" target that forwards to the +# right target (or no target) depending on the value of the build flag. This +# group can be in the same BUILD.gn file as the build flag, and targets can +# depend unconditionally on the group rather than duplicating flag checks +# across many targets. +# +# - If a semi-random set of build files REALLY needs to know about a define and +# the above pattern for isolating the build logic in a forwarding group +# doesn't work, you can put the argument in a .gni file. This should be put +# in the lowest level of the build that knows about this feature (which should +# almost always be outside of the //build directory!). +# +# Other flag advice: +# +# - Use boolean values when possible. If you need a default value that expands +# to some complex thing in the default case (like the location of the +# compiler which would be computed by a script), use a default value of -1 or +# the empty string. Outside of the declare_args block, conditionally expand +# the default value as necessary. +# +# - Use a name like "use_foo" or "is_foo" (whatever is more appropriate for +# your feature) rather than just "foo". +# +# - Write good comments directly above the declaration with no blank line. +# These comments will appear as documentation in "gn args --list". +# +# - Don't call exec_script inside declare_args. This will execute the script +# even if the value is overridden, which is wasteful. See first bullet. + +declare_args() { + # Set to enable the official build level of optimization. This has nothing + # to do with branding, but enables an additional level of optimization above + # release (!is_debug). This might be better expressed as a tri-state + # (debug, release, official) but for historical reasons there are two + # separate flags. + # + # IMPORTANT NOTE: (!is_debug) is *not* sufficient to get satisfying + # performance. In particular, DCHECK()s are still enabled for release builds, + # which can halve overall performance, and do increase memory usage. Always + # set "is_official_build" to true for any build intended to ship to end-users. + is_official_build = false + + # Set to true when compiling with the Clang compiler. + is_clang = current_os != "linux" || + (current_cpu != "s390x" && current_cpu != "s390" && + current_cpu != "ppc64" && current_cpu != "ppc" && + current_cpu != "mips" && current_cpu != "mips64" && + current_cpu != "riscv64") + + # Allows the path to a custom target toolchain to be injected as a single + # argument, and set as the default toolchain. + custom_toolchain = "" + + # This should not normally be set as a build argument. It's here so that + # every toolchain can pass through the "global" value via toolchain_args(). + host_toolchain = "" + + # Do not set this directly. + # It should be set only by //build/toolchains/android:robolectric_x64. + # True when compiling native code for use with robolectric_binary(). + is_robolectric = false + + # DON'T ADD MORE FLAGS HERE. Read the comment above. +} + +declare_args() { + # Debug build. Enabling official builds automatically sets is_debug to false. + is_debug = !is_official_build +} + +declare_args() { + # Component build. Setting to true compiles targets declared as "components" + # as shared libraries loaded dynamically. This speeds up development time. + # When false, components will be linked statically. + # + # For more information see + # https://chromium.googlesource.com/chromium/src/+/main/docs/component_build.md + is_component_build = is_debug && current_os != "ios" +} + +assert(!(is_debug && is_official_build), "Can't do official debug builds") +assert(!(current_os == "ios" && is_component_build), + "Can't use component build on iOS") + +# ============================================================================== +# TOOLCHAIN SETUP +# ============================================================================== +# +# Here we set the default toolchain, as well as the variable host_toolchain +# which will identify the toolchain corresponding to the local system when +# doing cross-compiles. When not cross-compiling, this will be the same as the +# default toolchain. +# +# We do this before anything else to make sure we complain about any +# unsupported os/cpu combinations as early as possible. + +if (host_toolchain == "") { + # This should only happen in the top-level context. + # In a specific toolchain context, the toolchain_args() + # block should have propagated a value down. + # TODO(dpranke): Add some sort of assert here that verifies that + # no toolchain omitted host_toolchain from its toolchain_args(). + + if (host_os == "linux") { + if (target_os != "linux") { + host_toolchain = "//build/toolchain/linux:clang_$host_cpu" + } else if (is_clang) { + host_toolchain = "//build/toolchain/linux:clang_$host_cpu" + } else { + host_toolchain = "//build/toolchain/linux:$host_cpu" + } + } else if (host_os == "mac") { + host_toolchain = "//build/toolchain/mac:clang_$host_cpu" + } else if (host_os == "win") { + # On Windows always use the target CPU for host builds for x86/x64. On the + # configurations we support this will always work and it saves build steps. + # Windows ARM64 targets require an x64 host for cross build. + if (target_cpu == "x86" || target_cpu == "x64") { + if (is_clang) { + host_toolchain = "//build/toolchain/win:win_clang_$target_cpu" + } else { + host_toolchain = "//build/toolchain/win:$target_cpu" + } + } else if (is_clang) { + host_toolchain = "//build/toolchain/win:win_clang_$host_cpu" + } else { + host_toolchain = "//build/toolchain/win:$host_cpu" + } + } else if (host_os == "aix") { + host_toolchain = "//build/toolchain/aix:$host_cpu" + } else if (host_os == "zos") { + host_toolchain = "//build/toolchain/zos:$host_cpu" + } else { + assert(false, "Unsupported host_os: $host_os") + } +} + +_default_toolchain = "" + +if (target_os == "android") { + assert(host_os == "linux", "Android builds are only supported on Linux.") + _default_toolchain = "//build/toolchain/android:android_clang_$target_cpu" +} else if (target_os == "chromeos" || target_os == "linux") { + # See comments in build/toolchain/cros/BUILD.gn about board compiles. + if (is_clang) { + _default_toolchain = "//build/toolchain/linux:clang_$target_cpu" + } else { + _default_toolchain = "//build/toolchain/linux:$target_cpu" + } +} else if (target_os == "fuchsia") { + _default_toolchain = "//build/toolchain/fuchsia:$target_cpu" +} else if (target_os == "ios") { + _default_toolchain = "//build/toolchain/ios:ios_clang_$target_cpu" +} else if (target_os == "mac") { + assert(host_os == "mac" || host_os == "linux", + "Mac cross-compiles are unsupported.") + _default_toolchain = "//build/toolchain/mac:clang_$target_cpu" +} else if (target_os == "win") { + # On Windows, we use the same toolchain for host and target by default. + # Beware, win cross builds have some caveats, see docs/win_cross.md + if (is_clang) { + _default_toolchain = "//build/toolchain/win:win_clang_$target_cpu" + } else { + _default_toolchain = "//build/toolchain/win:$target_cpu" + } +} else if (target_os == "winuwp") { + # Only target WinUWP on for a Windows store application and only + # x86, x64 and arm are supported target CPUs. + assert(target_cpu == "x86" || target_cpu == "x64" || target_cpu == "arm" || + target_cpu == "arm64") + _default_toolchain = "//build/toolchain/win:uwp_$target_cpu" +} else if (target_os == "aix") { + _default_toolchain = "//build/toolchain/aix:$target_cpu" +} else if (target_os == "zos") { + _default_toolchain = "//build/toolchain/zos:$target_cpu" +} else { + assert(false, "Unsupported target_os: $target_os") +} + +# If a custom toolchain has been set in the args, set it as default. Otherwise, +# set the default toolchain for the platform (if any). +if (custom_toolchain != "") { + set_default_toolchain(custom_toolchain) +} else if (_default_toolchain != "") { + set_default_toolchain(_default_toolchain) +} + +# ============================================================================= +# OS DEFINITIONS +# ============================================================================= +# +# We set these various is_FOO booleans for convenience in writing OS-based +# conditions. +# +# - is_android, is_chromeos, is_ios, and is_win should be obvious. +# - is_mac is set only for desktop Mac. It is not set on iOS. +# - is_posix is true for mac and any Unix-like system (basically everything +# except Fuchsia and Windows). +# - is_linux is true for desktop Linux, but not for ChromeOS nor Android (which +# is generally too different despite being based on the Linux kernel). +# +# Do not add more is_* variants here for random lesser-used Unix systems like +# aix or one of the BSDs. If you need to check these, just check the +# current_os value directly. + +is_android = current_os == "android" +is_chromeos = current_os == "chromeos" +is_fuchsia = current_os == "fuchsia" +is_ios = current_os == "ios" +is_linux = current_os == "linux" +is_mac = current_os == "mac" +is_nacl = current_os == "nacl" +is_win = current_os == "win" || current_os == "winuwp" + +is_apple = is_ios || is_mac +is_posix = !is_win && !is_fuchsia + +# ============================================================================= +# TARGET DEFAULTS +# ============================================================================= +# +# Set up the default configuration for every build target of the given type. +# The values configured here will be automatically set on the scope of the +# corresponding target. Target definitions can add or remove to the settings +# here as needed. +# +# WHAT GOES HERE? +# +# Other than the main compiler and linker configs, the only reason for a config +# to be in this list is if some targets need to explicitly override that config +# by removing it. This is how targets opt-out of flags. If you don't have that +# requirement and just need to add a config everywhere, reference it as a +# sub-config of an existing one, most commonly the main "compiler" one. + +# Holds all configs used for running the compiler. +default_compiler_configs = [ + "//build/config:feature_flags", + "//build/config/compiler:afdo", + "//build/config/compiler:afdo_optimize_size", + "//build/config/compiler:cet_shadow_stack", + "//build/config/compiler:chromium_code", + "//build/config/compiler:compiler", + "//build/config/compiler:compiler_arm_fpu", + "//build/config/compiler:compiler_arm_thumb", + "//build/config/compiler:default_include_dirs", + "//build/config/compiler:default_init_stack_vars", + "//build/config/compiler:default_optimization", + "//build/config/compiler:default_stack_frames", + "//build/config/compiler:default_symbols", + "//build/config/compiler:export_dynamic", + "//build/config/compiler:no_exceptions", + "//build/config/compiler:no_rtti", + "//build/config/compiler:no_unresolved_symbols", + "//build/config/compiler:runtime_library", + "//build/config/compiler:thin_archive", + "//build/config/compiler:thinlto_optimize_default", + "//build/config/compiler/pgo:default_pgo_flags", + "//build/config/coverage:default_coverage", + "//build/config/sanitizers:default_sanitizer_flags", +] + +if (is_win) { + default_compiler_configs += [ + "//build/config/win:default_cfg_compiler", + "//build/config/win:default_crt", + "//build/config/win:lean_and_mean", + "//build/config/win:nominmax", + "//build/config/win:unicode", + "//build/config/win:winver", + ] +} + +if (is_posix) { + if (current_os != "aix") { + default_compiler_configs += + [ "//build/config/gcc:symbol_visibility_hidden" ] + } +} + +if (is_fuchsia) { + default_compiler_configs += [ "//build/config/gcc:symbol_visibility_hidden" ] +} + +if (is_android) { + default_compiler_configs += + [ "//build/config/android:default_orderfile_instrumentation" ] +} + +if (is_clang && !is_nacl) { + default_compiler_configs += [ + "//build/config/clang:find_bad_constructs", + "//build/config/clang:extra_warnings", + ] +} + +# Debug/release-related defines. +if (is_debug) { + default_compiler_configs += [ "//build/config:debug" ] +} else { + default_compiler_configs += [ "//build/config:release" ] +} + +# ============================================================================= +# Begin PDFIUM MODIFICATIONS +# ============================================================================= +import("//pdfium.gni") +if (!pdf_use_cxx20) { + if (is_win && !is_clang) { + msvc_use_cxx17 = true + } else { + default_compiler_configs += [ "//build_overrides/compiler:force_cxx17" ] + } +} + +# ============================================================================= +# End PDFIUM MODIFICATIONS +# ============================================================================= + +# Static libraries and source sets use only the compiler ones. +set_defaults("static_library") { + configs = default_compiler_configs +} +set_defaults("source_set") { + configs = default_compiler_configs +} +set_defaults("rust_library") { + configs = default_compiler_configs +} +set_defaults("rust_proc_macro") { + configs = default_compiler_configs +} + +# Compute the set of configs common to all linked targets (shared libraries, +# loadable modules, executables) to avoid duplication below. +if (is_win) { + # Many targets remove these configs, so they are not contained within + # //build/config:executable_config for easy removal. + _linker_configs = [ + "//build/config/win:default_incremental_linking", + + # Default to console-mode apps. Most of our targets are tests and such + # that shouldn't use the windows subsystem. + "//build/config/win:console", + ] +} else if (is_mac) { + _linker_configs = [ "//build/config/apple:strip_all" ] +} else { + _linker_configs = [] +} + +# Executable defaults. +default_executable_configs = default_compiler_configs + [ + "//build/config:default_libs", + "//build/config:executable_config", + ] + _linker_configs + +if (is_win) { + # Turn on linker CFI for executables, and position it so it can be removed + # if needed. + default_executable_configs += [ "//build/config/win:cfi_linker" ] +} + +set_defaults("executable") { + configs = default_executable_configs +} + +# Shared library and loadable module defaults (also for components in component +# mode). +default_shared_library_configs = default_compiler_configs + [ + "//build/config:default_libs", + "//build/config:shared_library_config", + ] + _linker_configs +if (is_win) { + # Turn on linker CFI for DLLs, and position it so it can be removed if needed. + default_shared_library_configs += [ "//build/config/win:cfi_linker" ] +} + +if (is_android) { + # Strip native JNI exports from shared libraries by default. Binaries that + # want this can remove this config. + default_shared_library_configs += + [ "//build/config/android:hide_all_but_jni_onload" ] +} +set_defaults("shared_library") { + configs = default_shared_library_configs +} +set_defaults("loadable_module") { + configs = default_shared_library_configs + + # loadable_modules are generally used by other libs, not just via JNI. + if (is_android) { + configs -= [ "//build/config/android:hide_all_but_jni_onload" ] + } +} + +# A helper for forwarding testonly and visibility. +# Forwarding "*" does not include variables from outer scopes (to avoid copying +# all globals into each template invocation), so it will not pick up +# file-scoped or outer-template-scoped variables. Normally this behavior is +# desired, but "visibility" and "testonly" are commonly defined in outer scopes. +# Explicitly forwarding them in forward_variables_from() works around this +# nuance. See //build/docs/writing_gn_templates.md#using-forward_variables_from +TESTONLY_AND_VISIBILITY = [ + "testonly", + "visibility", +] + +# Sets default dependencies for executable and shared_library targets. +# +# Variables +# no_default_deps: If true, no standard dependencies will be added. +# Targets that set this usually also want to remove +# "//build/config/compiler:runtime_library" from configs (to remove +# its subconfig "//build/config/c++:runtime_library"). +foreach(_target_type, + [ + "executable", + "loadable_module", + "shared_library", + ]) { + template(_target_type) { + # Alias "target_name" because it is clobbered by forward_variables_from(). + _target_name = target_name + target(_target_type, _target_name) { + forward_variables_from(invoker, + "*", + TESTONLY_AND_VISIBILITY + [ "no_default_deps" ]) + forward_variables_from(invoker, TESTONLY_AND_VISIBILITY) + if (!defined(deps)) { + deps = [] + } + if (!defined(invoker.no_default_deps) || !invoker.no_default_deps) { + # This pulls in one of: + # //build/config:executable_deps + # //build/config:loadable_module_deps + # //build/config:shared_library_deps + # (This explicit list is so that grepping for these configs finds where + # they are used.) + deps += [ "//build/config:${_target_type}_deps" ] + } + + # On Android, write shared library output file to metadata. We will use + # this information to, for instance, collect all shared libraries that + # should be packaged into an APK. + if (!defined(invoker.metadata) && (is_android || is_robolectric) && + (_target_type == "shared_library" || + _target_type == "loadable_module")) { + _output_name = _target_name + if (defined(invoker.output_name)) { + _output_name = invoker.output_name + } + + # Remove 'lib' prefix from output name if it exists. + _magic_prefix = "$0x01$0x01" + _output_name = string_replace("${_magic_prefix}${_output_name}", + "${_magic_prefix}lib", + _magic_prefix, + 1) + _output_name = string_replace(_output_name, _magic_prefix, "", 1) + + if (defined(output_extension)) { + _shlib_extension = ".$output_extension" + } else if (is_component_build && _target_type != "loadable_module") { + _shlib_extension = ".cr.so" + } else { + _shlib_extension = ".so" + } + + metadata = { + shared_libraries = + [ "$root_out_dir/lib${_output_name}${_shlib_extension}" ] + } + } + } + } +} + +# ============================================================================== +# COMPONENT SETUP +# ============================================================================== + +# Defines a component, which equates to a shared_library when +# is_component_build == true and a static_library otherwise. +# +# Use static libraries for the static build rather than source sets because +# many of of our test binaries link many large dependencies but often don't +# use large portions of them. The static libraries are much more efficient to +# link in this situation since only the necessary object files are linked. +# +# The invoker can override the type of the target in the non-component-build +# case by setting static_component_type to either "source_set" or +# "static_library". If unset, the default will be used. +template("component") { + if (is_component_build) { + _component_mode = "shared_library" + } else if (defined(invoker.static_component_type)) { + assert(invoker.static_component_type == "static_library" || + invoker.static_component_type == "source_set") + _component_mode = invoker.static_component_type + } else if (!defined(invoker.sources) || invoker.sources == []) { + # When there are no sources defined, use a source set to avoid creating + # an empty static library (which generally don't work). + _component_mode = "source_set" + } else { + _component_mode = "static_library" + } + target(_component_mode, target_name) { + forward_variables_from(invoker, TESTONLY_AND_VISIBILITY) + forward_variables_from(invoker, "*", TESTONLY_AND_VISIBILITY) + } +} + +# Component defaults +# Set a variable since we also want to make this available +# to mixed_component.gni +if (is_component_build) { + default_component_configs = default_shared_library_configs + if (is_android) { + default_component_configs -= + [ "//build/config/android:hide_all_but_jni_onload" ] + } +} else { + default_component_configs = default_compiler_configs +} + +set_defaults("component") { + configs = default_component_configs +}
diff --git a/build_overrides/build.gni b/build_overrides/build.gni index bb15253..446fa89 100644 --- a/build_overrides/build.gni +++ b/build_overrides/build.gni
@@ -1,15 +1,7 @@ -# Copyright 2016 The Chromium Authors. All rights reserved. +# Copyright 2016 The PDFium Authors # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. -# See https://bugs.chromium.org/p/webrtc/issues/detail?id=5453. -# Some WebRTC targets require the 10.7 deployment version of the Mac SDK -# and a 10.11 min SDK, but those targets are only used in non-Chromium -# builds. We can remove this when Chromium drops 10.6 support and also -# requires 10.7. -mac_sdk_min_build_override = "10.10" -mac_deployment_target_build_override = "10.7" - # Variable that can be used to support multiple build scenarios, like having # Chromium specific targets in a client project's GN file etc. build_with_chromium = false @@ -22,14 +14,14 @@ # PDFium builds don't support building java targets. enable_java_templates = false +# Enables assertions on safety checks in libc++. +enable_safe_libcxx = true + # Whether to use the neon FPU instruction set or not. if (current_cpu == "arm") { arm_use_neon = true } -# PDFium builds don't use Chromium's third_party/binutils. -linux_use_bundled_binutils_override = false - # PDFium just uses the Chromium suppression files for now. asan_suppressions_file = "//build/sanitizers/asan_suppressions.cc" lsan_suppressions_file = "//build/sanitizers/lsan_suppressions.cc" @@ -47,6 +39,10 @@ # obtained with gclient sync after setting the environment variable # FORCE_MAC_TOOLCHAIN]. use_system_xcode = "" + + # Allows googletest to pretty-print various absl types. + # Assumes //third_party/abseil-cpp is an available dependency for googletest. + gtest_enable_absl_printers = true } if (use_system_xcode == "") {
diff --git a/build_overrides/compiler/BUILD.gn b/build_overrides/compiler/BUILD.gn new file mode 100644 index 0000000..b6cc641 --- /dev/null +++ b/build_overrides/compiler/BUILD.gn
@@ -0,0 +1,25 @@ +# Copyright 2022 The PDFium Authors +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +# A simplified config to consistently use C++17 and override the config +# in //build/config/compiler, which is using C++20 by default on many platforms. + +assert(!is_nacl) + +config("force_cxx17") { + cflags_cc = [] + + if (is_linux || is_chromeos || is_android || current_os == "aix") { + if (is_clang) { + standard_prefix = "c" + } else { + standard_prefix = "gnu" + } + cflags_cc += [ "-std=${standard_prefix}++17" ] + } else if (is_win) { + cflags_cc += [ "/std:c++17" ] + } else { + cflags_cc += [ "-std=c++17" ] + } +}
diff --git a/build_overrides/gtest.gni b/build_overrides/gtest.gni index bf30fb1..6afd879 100644 --- a/build_overrides/gtest.gni +++ b/build_overrides/gtest.gni
@@ -1,4 +1,4 @@ -# Copyright 2016 The Chromium Authors. All rights reserved. +# Copyright 2016 The PDFium Authors # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. @@ -8,7 +8,7 @@ # Exclude support for platform-specific operations across unit tests. gtest_include_platform_test = false -# Exclude support for testing Objective C code on OS X and iOS. +# Exclude support for testing Objective C code on macOS and iOS. gtest_include_objc_support = false # Exclude support for flushing coverage files on iOS.
diff --git a/build_overrides/partition_alloc.gni b/build_overrides/partition_alloc.gni new file mode 100644 index 0000000..0cf7009 --- /dev/null +++ b/build_overrides/partition_alloc.gni
@@ -0,0 +1,11 @@ +# Copyright 2022 The PDFium Authors +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +# See base/allocator/partition_allocator/external_builds.md +use_partition_alloc_as_malloc_default = false +enable_mte_checked_ptr_support_default = false +enable_backup_ref_ptr_support_default = false +put_ref_count_in_previous_slot_default = false +enable_backup_ref_ptr_slow_checks_default = false +enable_dangling_raw_ptr_checks_default = false
diff --git a/build_overrides/pdfium.gni b/build_overrides/pdfium.gni index ab89cd9..b7dc9e0 100644 --- a/build_overrides/pdfium.gni +++ b/build_overrides/pdfium.gni
@@ -1,4 +1,4 @@ -# Copyright 2016 The Chromium Authors. All rights reserved. +# Copyright 2016 The PDFium Authors # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. @@ -17,16 +17,13 @@ # Default: Without XFA support. pdf_enable_xfa_override = false -# Build PDFium against skia (experimental) rather than agg, replacing all PDFium -# graphics. -# Default: Use agg. +# Build PDFium with PartitionAlloc support, directing `fxcrt` to use +# it as its memory allocator in lieu of `malloc()`. +# Default: Use PartitionAlloc when building with Clang. +pdf_use_partition_alloc_override = is_clang + +# Build PDFium to use Skia (experimental) for all PDFium graphics. +# If enabled, coexists in build with AGG graphics and the default +# renderer is selectable at runtime. +# The default is to use AGG only when `pdf_use_skia_override` is false. pdf_use_skia_override = false - -# Build PDFium against skia (experimental) rather than agg, adding only path -# support. -# Default: Use agg. -pdf_use_skia_paths_override = false - -# Build PDFium either with or without experimental win32 GDI APIs. -# Default: Without experimental win32 GDI APIs. -pdf_use_win32_gdi_override = false
diff --git a/codereview.settings b/codereview.settings index 77265c9..a23bae5 100644 --- a/codereview.settings +++ b/codereview.settings
@@ -1,6 +1,6 @@ # This file is used by git cl to get repository specific information. +BUG_PREFIX: pdfium: CC_LIST: pdfium-reviews@googlegroups.com -CODE_REVIEW_SERVER: codereview.chromium.org GERRIT_HOST: True PROJECT: pdfium STATUS: http://pdfium-status.appspot.com/status
diff --git a/constants/Android.bp b/constants/Android.bp index caa06a7..9acfe51 100644 --- a/constants/Android.bp +++ b/constants/Android.bp
@@ -7,8 +7,12 @@ default_applicable_licenses: ["external_pdfium_license"], } -cc_library_headers { +cc_library_static { name: "libpdfium-constants", + defaults: ["pdfium-core"], export_include_dirs: ["."], visibility: ["//external/pdfium:__subpackages__"], + srcs: [ + "*.cpp", + ], }
diff --git a/constants/BUILD.gn b/constants/BUILD.gn index 4c10fed..3424743 100644 --- a/constants/BUILD.gn +++ b/constants/BUILD.gn
@@ -1,4 +1,4 @@ -# Copyright 2018 The PDFium Authors. All rights reserved. +# Copyright 2018 The PDFium Authors # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. @@ -6,12 +6,27 @@ source_set("constants") { sources = [ + "access_permissions.h", + "annotation_common.cpp", "annotation_common.h", "annotation_flags.h", + "appearance.cpp", + "appearance.h", + "ascii.h", + "font_encodings.cpp", + "font_encodings.h", + "form_fields.cpp", "form_fields.h", "form_flags.h", + "page_object.cpp", "page_object.h", + "stream_dict_common.cpp", "stream_dict_common.h", + "transparency.cpp", "transparency.h", ] + configs += [ + "../:pdfium_strict_config", + "../:pdfium_noshorten_config", + ] }
diff --git a/constants/access_permissions.h b/constants/access_permissions.h new file mode 100644 index 0000000..b95f7e9 --- /dev/null +++ b/constants/access_permissions.h
@@ -0,0 +1,21 @@ +// Copyright 2020 The PDFium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CONSTANTS_ACCESS_PERMISSIONS_H_ +#define CONSTANTS_ACCESS_PERMISSIONS_H_ + +namespace pdfium { +namespace access_permissions { + +// PDF 1.7 spec, table 3.20. +// User access permissions. +constexpr uint32_t kModifyContent = 1 << 3; +constexpr uint32_t kModifyAnnotation = 1 << 5; +constexpr uint32_t kFillForm = 1 << 8; +constexpr uint32_t kExtractForAccessibility = 1 << 9; + +} // namespace access_permissions +} // namespace pdfium + +#endif // CONSTANTS_ACCESS_PERMISSIONS_H_
diff --git a/constants/annotation_common.cpp b/constants/annotation_common.cpp new file mode 100644 index 0000000..6110e38 --- /dev/null +++ b/constants/annotation_common.cpp
@@ -0,0 +1,37 @@ +// Copyright 2021 The PDFium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "constants/annotation_common.h" + +namespace pdfium { +namespace annotation { + +// PDF 1.7 spec, table 8.15. +// Entries common to all annotation dictionaries. +const char kType[] = "Type"; +const char kSubtype[] = "Subtype"; +const char kRect[] = "Rect"; +const char kContents[] = "Contents"; +const char kP[] = "P"; +const char kNM[] = "NM"; +const char kM[] = "M"; +const char kF[] = "F"; +const char kAP[] = "AP"; +const char kAS[] = "AS"; +const char kBorder[] = "Border"; +const char kC[] = "C"; +const char kStructParent[] = "StructParent"; +const char kOC[] = "OC"; + +// Entries for polygon and polyline annotations. +const char kVertices[] = "Vertices"; + +// Entries for ink annotations +const char kInkList[] = "InkList"; + +// Entries for line annotations +const char kL[] = "L"; + +} // namespace annotation +} // namespace pdfium
diff --git a/constants/annotation_common.h b/constants/annotation_common.h index 471d244..baf0677 100644 --- a/constants/annotation_common.h +++ b/constants/annotation_common.h
@@ -1,4 +1,4 @@ -// Copyright 2019 PDFium Authors. All rights reserved. +// Copyright 2019 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -8,23 +8,26 @@ namespace pdfium { namespace annotation { -// PDF 1.7 spec, table 8.15. -// Entries common to all annotation dictionaries. +extern const char kType[]; +extern const char kSubtype[]; +extern const char kRect[]; +extern const char kContents[]; +extern const char kP[]; +extern const char kNM[]; +extern const char kM[]; +extern const char kF[]; +extern const char kAP[]; +extern const char kAS[]; +extern const char kBorder[]; +extern const char kC[]; +extern const char kStructParent[]; +extern const char kOC[]; -constexpr char kType[] = "Type"; -constexpr char kSubtype[] = "Subtype"; -constexpr char kRect[] = "Rect"; -constexpr char kContents[] = "Contents"; -constexpr char kP[] = "P"; -constexpr char kNM[] = "NM"; -constexpr char kM[] = "M"; -constexpr char kF[] = "F"; -constexpr char kAP[] = "AP"; -constexpr char kAS[] = "AS"; -constexpr char kBorder[] = "Border"; -constexpr char kC[] = "C"; -constexpr char kStructParent[] = "StructParent"; -constexpr char kOC[] = "OC"; +extern const char kVertices[]; + +extern const char kInkList[]; + +extern const char kL[]; } // namespace annotation } // namespace pdfium
diff --git a/constants/annotation_flags.h b/constants/annotation_flags.h index d2731da..d44a0c1 100644 --- a/constants/annotation_flags.h +++ b/constants/annotation_flags.h
@@ -1,10 +1,12 @@ -// Copyright 2019 PDFium Authors. All rights reserved. +// Copyright 2019 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #ifndef CONSTANTS_ANNOTATION_FLAGS_H_ #define CONSTANTS_ANNOTATION_FLAGS_H_ +#include <stdint.h> + namespace pdfium { namespace annotation_flags {
diff --git a/constants/appearance.cpp b/constants/appearance.cpp new file mode 100644 index 0000000..3ccdddd --- /dev/null +++ b/constants/appearance.cpp
@@ -0,0 +1,23 @@ +// Copyright 2021 The PDFium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "constants/appearance.h" + +namespace pdfium { +namespace appearance { + +// ISO 32000-1:2008 spec, table 189. +// Entries in an appearance characteristics dictionary. +const char kR[] = "R"; +const char kBC[] = "BC"; +const char kBG[] = "BG"; +const char kCA[] = "CA"; +const char kRC[] = "RC"; +const char kAC[] = "AC"; +const char kI[] = "I"; +const char kRI[] = "RI"; +const char kIX[] = "IX"; + +} // namespace appearance +} // namespace pdfium
diff --git a/constants/appearance.h b/constants/appearance.h new file mode 100644 index 0000000..2a5b752 --- /dev/null +++ b/constants/appearance.h
@@ -0,0 +1,24 @@ +// Copyright 2021 The PDFium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CONSTANTS_APPEARANCE_H_ +#define CONSTANTS_APPEARANCE_H_ + +namespace pdfium { +namespace appearance { + +extern const char kR[]; +extern const char kBC[]; +extern const char kBG[]; +extern const char kCA[]; +extern const char kRC[]; +extern const char kAC[]; +extern const char kI[]; +extern const char kRI[]; +extern const char kIX[]; + +} // namespace appearance +} // namespace pdfium + +#endif // CONSTANTS_APPEARANCE_H_
diff --git a/constants/ascii.h b/constants/ascii.h new file mode 100644 index 0000000..2f64419 --- /dev/null +++ b/constants/ascii.h
@@ -0,0 +1,30 @@ +// Copyright 2021 The PDFium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CONSTANTS_ASCII_H_ +#define CONSTANTS_ASCII_H_ + +#include <stdint.h> + +namespace pdfium { +namespace ascii { + +constexpr uint8_t kNul = 0x00; +constexpr uint8_t kControlA = 0x01; +constexpr uint8_t kControlB = 0x02; +constexpr uint8_t kControlC = 0x03; +constexpr uint8_t kBackspace = 0x08; +constexpr uint8_t kTab = 0x09; +constexpr uint8_t kNewline = 0x0a; +constexpr uint8_t kReturn = 0x0d; +constexpr uint8_t kControlV = 0x16; +constexpr uint8_t kControlX = 0x18; +constexpr uint8_t kControlZ = 0x1a; +constexpr uint8_t kEscape = 0x1b; +constexpr uint8_t kSpace = 0x20; + +} // namespace ascii +} // namespace pdfium + +#endif // CONSTANTS_ASCII_H_
diff --git a/constants/font_encodings.cpp b/constants/font_encodings.cpp new file mode 100644 index 0000000..4359701 --- /dev/null +++ b/constants/font_encodings.cpp
@@ -0,0 +1,17 @@ +// Copyright 2022 The PDFium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "constants/font_encodings.h" + +namespace pdfium { +namespace font_encodings { + +// ISO 32000-1:2008 spec, table D1. +const char kMacRomanEncoding[] = "MacRomanEncoding"; +const char kWinAnsiEncoding[] = "WinAnsiEncoding"; +const char kPDFDocEncoding[] = "PDFDocEncoding"; +const char kMacExpertEncoding[] = "MacExpertEncoding"; + +} // namespace font_encodings +} // namespace pdfium
diff --git a/constants/font_encodings.h b/constants/font_encodings.h new file mode 100644 index 0000000..aefd9f1 --- /dev/null +++ b/constants/font_encodings.h
@@ -0,0 +1,19 @@ +// Copyright 2022 The PDFium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CONSTANTS_FONT_ENCODINGS_H_ +#define CONSTANTS_FONT_ENCODINGS_H_ + +namespace pdfium { +namespace font_encodings { + +extern const char kMacRomanEncoding[]; +extern const char kWinAnsiEncoding[]; +extern const char kPDFDocEncoding[]; +extern const char kMacExpertEncoding[]; + +} // namespace font_encodings +} // namespace pdfium + +#endif // CONSTANTS_FONT_ENCODINGS_H_
diff --git a/constants/form_fields.cpp b/constants/form_fields.cpp new file mode 100644 index 0000000..32ef84c --- /dev/null +++ b/constants/form_fields.cpp
@@ -0,0 +1,38 @@ +// Copyright 2021 The PDFium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "constants/form_fields.h" + +namespace pdfium { +namespace form_fields { + +// ISO 32000-1:2008 table 220. +// Entries common to all field dictionaries. +const char kFT[] = "FT"; +const char kParent[] = "Parent"; +const char kKids[] = "Kids"; +const char kT[] = "T"; +const char kTU[] = "TU"; +const char kTM[] = "TM"; +const char kFf[] = "Ff"; +const char kV[] = "V"; +const char kDV[] = "DV"; +const char kAA[] = "AA"; + +// ISO 32000-1:2008 table 220. +// Values for FT keyword. +const char kBtn[] = "Btn"; +const char kTx[] = "Tx"; +const char kCh[] = "Ch"; +const char kSig[] = "Sig"; + +// ISO 32000-1:2008 table 222. +// Entries common to fields containing variable text. +const char kDA[] = "DA"; +const char kQ[] = "Q"; +const char kDS[] = "DS"; +const char kRV[] = "RV"; + +} // namespace form_fields +} // namespace pdfium
diff --git a/constants/form_fields.h b/constants/form_fields.h index 5b7c169..129bbd3 100644 --- a/constants/form_fields.h +++ b/constants/form_fields.h
@@ -1,4 +1,4 @@ -// Copyright 2019 PDFium Authors. All rights reserved. +// Copyright 2019 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -8,24 +8,26 @@ namespace pdfium { namespace form_fields { -// PDF 1.7 spec, table 8.69. -// Entries common to all field dictionaries. -constexpr char kFT[] = "FT"; -constexpr char kParent[] = "Parent"; -constexpr char kKids[] = "Kids"; -constexpr char kT[] = "T"; -constexpr char kTU[] = "TU"; -constexpr char kTM[] = "TM"; -constexpr char kFf[] = "Ff"; -constexpr char kV[] = "V"; -constexpr char kDV[] = "DV"; -constexpr char kAA[] = "AA"; +extern const char kFT[]; +extern const char kParent[]; +extern const char kKids[]; +extern const char kT[]; +extern const char kTU[]; +extern const char kTM[]; +extern const char kFf[]; +extern const char kV[]; +extern const char kDV[]; +extern const char kAA[]; -// FT values from PDF 1.7 spec, table 8.69. -constexpr char kBtn[] = "Btn"; -constexpr char kTx[] = "Tx"; -constexpr char kCh[] = "Ch"; -constexpr char kSig[] = "Sig"; +extern const char kBtn[]; +extern const char kTx[]; +extern const char kCh[]; +extern const char kSig[]; + +extern const char kDA[]; +extern const char kQ[]; +extern const char kDS[]; +extern const char kRV[]; } // namespace form_fields } // namespace pdfium
diff --git a/constants/form_flags.h b/constants/form_flags.h index 148bb4c..602a164 100644 --- a/constants/form_flags.h +++ b/constants/form_flags.h
@@ -1,4 +1,4 @@ -// Copyright 2018 PDFium Authors. All rights reserved. +// Copyright 2018 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file.
diff --git a/constants/page_object.cpp b/constants/page_object.cpp new file mode 100644 index 0000000..0a3e068 --- /dev/null +++ b/constants/page_object.cpp
@@ -0,0 +1,24 @@ +// Copyright 2021 The PDFium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "constants/page_object.h" + +namespace pdfium { +namespace page_object { + +// PDF 1.7 spec, table 3.27. +// Entries in a page object. +const char kType[] = "Type"; +const char kParent[] = "Parent"; +const char kResources[] = "Resources"; +const char kMediaBox[] = "MediaBox"; +const char kCropBox[] = "CropBox"; +const char kBleedBox[] = "BleedBox"; +const char kTrimBox[] = "TrimBox"; +const char kArtBox[] = "ArtBox"; +const char kContents[] = "Contents"; +const char kRotate[] = "Rotate"; + +} // namespace page_object +} // namespace pdfium
diff --git a/constants/page_object.h b/constants/page_object.h index 8a41b8c..6fb7d68 100644 --- a/constants/page_object.h +++ b/constants/page_object.h
@@ -1,4 +1,4 @@ -// Copyright 2018 PDFium Authors. All rights reserved. +// Copyright 2018 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -8,19 +8,16 @@ namespace pdfium { namespace page_object { -// PDF 1.7 spec, table 3.27. -// Entries in a page object. - -constexpr char kType[] = "Type"; -constexpr char kParent[] = "Parent"; -constexpr char kResources[] = "Resources"; -constexpr char kMediaBox[] = "MediaBox"; -constexpr char kCropBox[] = "CropBox"; -constexpr char kBleedBox[] = "BleedBox"; -constexpr char kTrimBox[] = "TrimBox"; -constexpr char kArtBox[] = "ArtBox"; -constexpr char kContents[] = "Contents"; -constexpr char kRotate[] = "Rotate"; +extern const char kType[]; +extern const char kParent[]; +extern const char kResources[]; +extern const char kMediaBox[]; +extern const char kCropBox[]; +extern const char kBleedBox[]; +extern const char kTrimBox[]; +extern const char kArtBox[]; +extern const char kContents[]; +extern const char kRotate[]; } // namespace page_object } // namespace pdfium
diff --git a/constants/stream_dict_common.cpp b/constants/stream_dict_common.cpp new file mode 100644 index 0000000..5d294c4 --- /dev/null +++ b/constants/stream_dict_common.cpp
@@ -0,0 +1,22 @@ +// Copyright 2021 The PDFium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "constants/stream_dict_common.h" + +namespace pdfium { +namespace stream { + +// PDF 1.7 spec, table 3.4. +// Entries common to all stream dictionaries. +// +// TODO(https://crbug.com/pdfium/1049): Examine all usages of "Length", +// "Filter", and "F". +const char kLength[] = "Length"; +const char kFilter[] = "Filter"; +const char kDecodeParms[] = "DecodeParms"; +const char kF[] = "F"; +const char kDL[] = "DL"; + +} // namespace stream +} // namespace pdfium
diff --git a/constants/stream_dict_common.h b/constants/stream_dict_common.h index fc12622..feb887a 100644 --- a/constants/stream_dict_common.h +++ b/constants/stream_dict_common.h
@@ -1,4 +1,4 @@ -// Copyright 2018 PDFium Authors. All rights reserved. +// Copyright 2018 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -8,18 +8,11 @@ namespace pdfium { namespace stream { -// PDF 1.7 spec, table 3.4. -// Entries common to all stream dictionaries. - -// TODO(https://crbug.com/pdfium/1049): Examine all usages of "Length", -// "Filter", and "F". -constexpr char kLength[] = "Length"; -constexpr char kFilter[] = "Filter"; -constexpr char kDecodeParms[] = "DecodeParms"; -constexpr char kF[] = "F"; -// constexpr char kFFilter[] = "FFilter"; -// constexpr char kFDecodeParms[] = "FDecodeParms"; -constexpr char kDL[] = "DL"; +extern const char kLength[]; +extern const char kFilter[]; +extern const char kDecodeParms[]; +extern const char kF[]; +extern const char kDL[]; } // namespace stream } // namespace pdfium
diff --git a/constants/transparency.cpp b/constants/transparency.cpp new file mode 100644 index 0000000..11b8703 --- /dev/null +++ b/constants/transparency.cpp
@@ -0,0 +1,48 @@ +// Copyright 2021 The PDFium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "constants/transparency.h" + +namespace pdfium { +namespace transparency { + +// PDF 1.7 spec, table 7.2. +// Standard separable blend modes. +const char kNormal[] = "Normal"; +const char kMultiply[] = "Multiply"; +const char kScreen[] = "Screen"; +const char kOverlay[] = "Overlay"; +const char kDarken[] = "Darken"; +const char kLighten[] = "Lighten"; +const char kColorDodge[] = "ColorDodge"; +const char kColorBurn[] = "ColorBurn"; +const char kHardLight[] = "HardLight"; +const char kSoftLight[] = "SoftLight"; +const char kDifference[] = "Difference"; +const char kExclusion[] = "Exclusion"; + +// PDF 1.7 spec, table 7.3. +// Standard nonseparable blend modes. +const char kHue[] = "Hue"; +const char kSaturation[] = "Saturation"; +const char kColor[] = "Color"; +const char kLuminosity[] = "Luminosity"; + +// PDF 1.7 spec, table 7.10. +// Entries in a soft-mask dictionary. +const char kSoftMaskSubType[] = "S"; +const char kAlpha[] = "Alpha"; +const char kG[] = "G"; +const char kBC[] = "BC"; +const char kTR[] = "TR"; + +// PDF 1.7 spec, table 7.13. +// Additional entries specific to a transparency group attributes dictionary. +const char kGroupSubType[] = "S"; +const char kTransparency[] = "Transparency"; +const char kCS[] = "CS"; +const char kI[] = "I"; + +} // namespace transparency +} // namespace pdfium
diff --git a/constants/transparency.h b/constants/transparency.h index 6532868..21b22c4 100644 --- a/constants/transparency.h +++ b/constants/transparency.h
@@ -1,4 +1,4 @@ -// Copyright 2018 PDFium Authors. All rights reserved. +// Copyright 2018 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -8,46 +8,34 @@ namespace pdfium { namespace transparency { -// PDF 1.7 spec, table 7.2. -// Standard separable blend modes. +extern const char kNormal[]; +extern const char kMultiply[]; +extern const char kScreen[]; +extern const char kOverlay[]; +extern const char kDarken[]; +extern const char kLighten[]; +extern const char kColorDodge[]; +extern const char kColorBurn[]; +extern const char kHardLight[]; +extern const char kSoftLight[]; +extern const char kDifference[]; +extern const char kExclusion[]; -constexpr char kNormal[] = "Normal"; -constexpr char kMultiply[] = "Multiply"; -constexpr char kScreen[] = "Screen"; -constexpr char kOverlay[] = "Overlay"; -constexpr char kDarken[] = "Darken"; -constexpr char kLighten[] = "Lighten"; -constexpr char kColorDodge[] = "ColorDodge"; -constexpr char kColorBurn[] = "ColorBurn"; -constexpr char kHardLight[] = "HardLight"; -constexpr char kSoftLight[] = "SoftLight"; -constexpr char kDifference[] = "Difference"; -constexpr char kExclusion[] = "Exclusion"; +extern const char kHue[]; +extern const char kSaturation[]; +extern const char kColor[]; +extern const char kLuminosity[]; -// PDF 1.7 spec, table 7.3. -// Standard nonseparable blend modes. +extern const char kSoftMaskSubType[]; +extern const char kAlpha[]; +extern const char kG[]; +extern const char kBC[]; +extern const char kTR[]; -constexpr char kHue[] = "Hue"; -constexpr char kSaturation[] = "Saturation"; -constexpr char kColor[] = "Color"; -constexpr char kLuminosity[] = "Luminosity"; - -// PDF 1.7 spec, table 7.10. -// Entries in a soft-mask dictionary. - -constexpr char kSoftMaskSubType[] = "S"; -constexpr char kAlpha[] = "Alpha"; -constexpr char kG[] = "G"; -constexpr char kBC[] = "BC"; -constexpr char kTR[] = "TR"; - -// PDF 1.7 spec, table 7.13. -// Additional entries specific to a transparency group attributes dictionary. - -constexpr char kGroupSubType[] = "S"; -constexpr char kTransparency[] = "Transparency"; -constexpr char kCS[] = "CS"; -constexpr char kI[] = "I"; +extern const char kGroupSubType[]; +extern const char kTransparency[]; +extern const char kCS[]; +extern const char kI[]; } // namespace transparency } // namespace pdfium
diff --git a/core/fdrm/BUILD.gn b/core/fdrm/BUILD.gn index 888bb92..1ee3162 100644 --- a/core/fdrm/BUILD.gn +++ b/core/fdrm/BUILD.gn
@@ -1,4 +1,4 @@ -# Copyright 2018 The PDFium Authors. All rights reserved. +# Copyright 2018 The PDFium Authors # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. @@ -12,7 +12,10 @@ "fx_crypt_aes.cpp", "fx_crypt_sha.cpp", ] - configs += [ "../../:pdfium_core_config" ] + configs += [ + "../../:pdfium_strict_config", + "../../:pdfium_noshorten_config", + ] deps = [ "../fxcrt" ] visibility = [ "../../*" ] }
diff --git a/core/fdrm/fx_crypt.cpp b/core/fdrm/fx_crypt.cpp index 7cc0bc0..c702f92 100644 --- a/core/fdrm/fx_crypt.cpp +++ b/core/fdrm/fx_crypt.cpp
@@ -1,4 +1,4 @@ -// Copyright 2014 PDFium Authors. All rights reserved. +// Copyright 2014 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -8,6 +8,8 @@ #include <utility> +#include "core/fxcrt/span_util.h" + #define GET_UINT32(n, b, i) \ { \ (n) = (uint32_t)((uint8_t*)b)[(i)] | \ @@ -31,7 +33,7 @@ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; void md5_process(CRYPT_md5_context* ctx, const uint8_t data[64]) { - uint32_t A, B, C, D, X[16]; + uint32_t X[16]; GET_UINT32(X[0], data, 0); GET_UINT32(X[1], data, 4); GET_UINT32(X[2], data, 8); @@ -48,16 +50,16 @@ GET_UINT32(X[13], data, 52); GET_UINT32(X[14], data, 56); GET_UINT32(X[15], data, 60); + uint32_t A = ctx->state[0]; + uint32_t B = ctx->state[1]; + uint32_t C = ctx->state[2]; + uint32_t D = ctx->state[3]; #define S(x, n) ((x << n) | ((x & 0xFFFFFFFF) >> (32 - n))) #define P(a, b, c, d, k, s, t) \ { \ a += F(b, c, d) + X[k] + t; \ a = S(a, s) + b; \ } - A = ctx->state[0]; - B = ctx->state[1]; - C = ctx->state[2]; - D = ctx->state[3]; #define F(x, y, z) (z ^ (x & (y ^ z))) P(A, B, C, D, 0, 7, 0xD76AA478); P(D, A, B, C, 1, 12, 0xE8C7B756); @@ -142,11 +144,11 @@ pdfium::span<const uint8_t> key) { context->x = 0; context->y = 0; - for (int i = 0; i < kRC4ContextPermutationLength; ++i) + for (int i = 0; i < CRYPT_rc4_context::kPermutationLength; ++i) context->m[i] = i; int j = 0; - for (int i = 0; i < kRC4ContextPermutationLength; ++i) { + for (int i = 0; i < CRYPT_rc4_context::kPermutationLength; ++i) { size_t size = key.size(); j = (j + context->m[i] + (size ? key[i % size] : 0)) & 0xFF; std::swap(context->m[i], context->m[j]); @@ -193,21 +195,20 @@ context->total[1] += data.size() >> 29; context->total[0] &= 0xFFFFFFFF; context->total[1] += context->total[0] < data.size() << 3; + + const pdfium::span<uint8_t> buffer_span = pdfium::make_span(context->buffer); if (left && data.size() >= fill) { - auto next_data = data.subspan(fill); - memcpy(context->buffer + left, data.data(), fill); + fxcrt::spancpy(buffer_span.subspan(left), data.first(fill)); md5_process(context, context->buffer); + data = data.subspan(fill); left = 0; - data = next_data; } while (data.size() >= 64) { - auto next_data = data.subspan(64); md5_process(context, data.data()); - data = next_data; + data = data.subspan(64); } - size_t remaining = data.size(); - if (remaining) - memcpy(context->buffer + left, data.data(), remaining); + if (!data.empty()) + fxcrt::spancpy(buffer_span.subspan(left), data); } void CRYPT_MD5Finish(CRYPT_md5_context* context, uint8_t digest[16]) { @@ -216,7 +217,7 @@ PUT_UINT32(context->total[1], msglen, 4); uint32_t last = (context->total[0] >> 3) & 0x3F; uint32_t padn = (last < 56) ? (56 - last) : (120 - last); - CRYPT_MD5Update(context, {md5_padding, padn}); + CRYPT_MD5Update(context, pdfium::make_span(md5_padding).first(padn)); CRYPT_MD5Update(context, msglen); PUT_UINT32(context->state[0], digest, 0); PUT_UINT32(context->state[1], digest, 4);
diff --git a/core/fdrm/fx_crypt.h b/core/fdrm/fx_crypt.h index f3a91f4..f3171c7 100644 --- a/core/fdrm/fx_crypt.h +++ b/core/fdrm/fx_crypt.h
@@ -1,4 +1,4 @@ -// Copyright 2014 PDFium Authors. All rights reserved. +// Copyright 2014 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -7,24 +7,28 @@ #ifndef CORE_FDRM_FX_CRYPT_H_ #define CORE_FDRM_FX_CRYPT_H_ -#include "core/fxcrt/fx_system.h" +#include <stdint.h> + #include "third_party/base/span.h" -constexpr int32_t kRC4ContextPermutationLength = 256; struct CRYPT_rc4_context { + static constexpr int32_t kPermutationLength = 256; + int32_t x; int32_t y; - int32_t m[kRC4ContextPermutationLength]; + int32_t m[kPermutationLength]; }; -#define MAX_NR 14 -#define MAX_NB 8 struct CRYPT_aes_context { + static constexpr int kMaxNb = 8; + static constexpr int kMaxNr = 14; + static constexpr int kSchedSize = (kMaxNr + 1) * kMaxNb; + int Nb; int Nr; - unsigned int keysched[(MAX_NR + 1) * MAX_NB]; - unsigned int invkeysched[(MAX_NR + 1) * MAX_NB]; - unsigned int iv[MAX_NB]; + unsigned int keysched[kSchedSize]; + unsigned int invkeysched[kSchedSize]; + unsigned int iv[kMaxNb]; }; struct CRYPT_md5_context { @@ -54,8 +58,7 @@ void CRYPT_AESSetKey(CRYPT_aes_context* context, const uint8_t* key, - uint32_t keylen, - bool bEncrypt); + uint32_t keylen); void CRYPT_AESSetIV(CRYPT_aes_context* context, const uint8_t* iv); void CRYPT_AESDecrypt(CRYPT_aes_context* context, uint8_t* dest,
diff --git a/core/fdrm/fx_crypt_aes.cpp b/core/fdrm/fx_crypt_aes.cpp index d4e446f..3fab02f 100644 --- a/core/fdrm/fx_crypt_aes.cpp +++ b/core/fdrm/fx_crypt_aes.cpp
@@ -1,4 +1,4 @@ -// Copyright 2014 PDFium Authors. All rights reserved. +// Copyright 2014 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -6,12 +6,13 @@ #include "core/fdrm/fx_crypt.h" +#include <string.h> + +#include "core/fxcrt/fx_system.h" +#include "third_party/base/check.h" +#include "third_party/base/check_op.h" + #define mulby2(x) (((x & 0x7F) << 1) ^ (x & 0x80 ? 0x1B : 0)) -#define GET_32BIT_MSB_FIRST(cp) \ - (((unsigned long)(unsigned char)(cp)[3]) | \ - ((unsigned long)(unsigned char)(cp)[2] << 8) | \ - ((unsigned long)(unsigned char)(cp)[1] << 16) | \ - ((unsigned long)(unsigned char)(cp)[0] << 24)) #define PUT_32BIT_MSB_FIRST(cp, value) \ do { \ (cp)[3] = (value); \ @@ -428,12 +429,11 @@ 0x3c498b28, 0x0d9541ff, 0xa8017139, 0x0cb3de08, 0xb4e49cd8, 0x56c19064, 0xcb84617b, 0x32b670d5, 0x6c5c7448, 0xb85742d0, }; -#define ADD_ROUND_KEY_4 \ +#define ADD_ROUND_KEY_4() \ (block[0] ^= *keysched++, block[1] ^= *keysched++, block[2] ^= *keysched++, \ block[3] ^= *keysched++) #define MOVEWORD(i) (block[i] = newstate[i]) -#undef MAKEWORD -#define MAKEWORD(i) \ +#define FMAKEWORD(i) \ (newstate[i] = (E0[(block[i] >> 24) & 0xFF] ^ \ E1[(block[(i + C1) % Nb] >> 16) & 0xFF] ^ \ E2[(block[(i + C2) % Nb] >> 8) & 0xFF] ^ \ @@ -446,21 +446,24 @@ void aes_encrypt_nb_4(CRYPT_aes_context* ctx, unsigned int* block) { int i; - const int C1 = 1, C2 = 2, C3 = 3, Nb = 4; + const int C1 = 1; + const int C2 = 2; + const int C3 = 3; + const int Nb = 4; unsigned int* keysched = ctx->keysched; unsigned int newstate[4]; for (i = 0; i < ctx->Nr - 1; i++) { - ADD_ROUND_KEY_4; - MAKEWORD(0); - MAKEWORD(1); - MAKEWORD(2); - MAKEWORD(3); + ADD_ROUND_KEY_4(); + FMAKEWORD(0); + FMAKEWORD(1); + FMAKEWORD(2); + FMAKEWORD(3); MOVEWORD(0); MOVEWORD(1); MOVEWORD(2); MOVEWORD(3); } - ADD_ROUND_KEY_4; + ADD_ROUND_KEY_4(); LASTWORD(0); LASTWORD(1); LASTWORD(2); @@ -469,12 +472,12 @@ MOVEWORD(1); MOVEWORD(2); MOVEWORD(3); - ADD_ROUND_KEY_4; + ADD_ROUND_KEY_4(); } -#undef MAKEWORD +#undef FMAKEWORD #undef LASTWORD -#define MAKEWORD(i) \ +#define FMAKEWORD(i) \ (newstate[i] = (D0[(block[i] >> 24) & 0xFF] ^ \ D1[(block[(i + C1) % Nb] >> 16) & 0xFF] ^ \ D2[(block[(i + C2) % Nb] >> 8) & 0xFF] ^ \ @@ -487,21 +490,24 @@ void aes_decrypt_nb_4(CRYPT_aes_context* ctx, unsigned int* block) { int i; - const int C1 = 4 - 1, C2 = 4 - 2, C3 = 4 - 3, Nb = 4; + const int C1 = 4 - 1; + const int C2 = 4 - 2; + const int C3 = 4 - 3; + const int Nb = 4; unsigned int* keysched = ctx->invkeysched; unsigned int newstate[4]; for (i = 0; i < ctx->Nr - 1; i++) { - ADD_ROUND_KEY_4; - MAKEWORD(0); - MAKEWORD(1); - MAKEWORD(2); - MAKEWORD(3); + ADD_ROUND_KEY_4(); + FMAKEWORD(0); + FMAKEWORD(1); + FMAKEWORD(2); + FMAKEWORD(3); MOVEWORD(0); MOVEWORD(1); MOVEWORD(2); MOVEWORD(3); } - ADD_ROUND_KEY_4; + ADD_ROUND_KEY_4(); LASTWORD(0); LASTWORD(1); LASTWORD(2); @@ -510,39 +516,37 @@ MOVEWORD(1); MOVEWORD(2); MOVEWORD(3); - ADD_ROUND_KEY_4; + ADD_ROUND_KEY_4(); } -#undef MAKEWORD +#undef FMAKEWORD #undef LASTWORD void aes_setup(CRYPT_aes_context* ctx, const unsigned char* key, int keylen) { - ASSERT(keylen == 16 || keylen == 24 || keylen == 32); + DCHECK(keylen == 16 || keylen == 24 || keylen == 32); int Nk = keylen / 4; ctx->Nb = 4; ctx->Nr = 6 + (ctx->Nb > Nk ? ctx->Nb : Nk); int rconst = 1; for (int i = 0; i < (ctx->Nr + 1) * ctx->Nb; i++) { if (i < Nk) { - ctx->keysched[i] = GET_32BIT_MSB_FIRST(key + 4 * i); + ctx->keysched[i] = FXSYS_UINT32_GET_MSBFIRST(key + 4 * i); } else { unsigned int temp = ctx->keysched[i - 1]; if (i % Nk == 0) { - int a, b, c, d; - a = (temp >> 16) & 0xFF; - b = (temp >> 8) & 0xFF; - c = (temp >> 0) & 0xFF; - d = (temp >> 24) & 0xFF; + int a = (temp >> 16) & 0xFF; + int b = (temp >> 8) & 0xFF; + int c = (temp >> 0) & 0xFF; + int d = (temp >> 24) & 0xFF; temp = Sbox[a] ^ rconst; temp = (temp << 8) | Sbox[b]; temp = (temp << 8) | Sbox[c]; temp = (temp << 8) | Sbox[d]; rconst = mulby2(rconst); } else if (i % Nk == 4 && Nk > 6) { - int a, b, c, d; - a = (temp >> 24) & 0xFF; - b = (temp >> 16) & 0xFF; - c = (temp >> 8) & 0xFF; - d = (temp >> 0) & 0xFF; + int a = (temp >> 24) & 0xFF; + int b = (temp >> 16) & 0xFF; + int c = (temp >> 8) & 0xFF; + int d = (temp >> 0) & 0xFF; temp = Sbox[a]; temp = (temp << 8) | Sbox[b]; temp = (temp << 8) | Sbox[c]; @@ -556,11 +560,10 @@ unsigned int temp; temp = ctx->keysched[(ctx->Nr - i) * ctx->Nb + j]; if (i != 0 && i != ctx->Nr) { - int a, b, c, d; - a = (temp >> 24) & 0xFF; - b = (temp >> 16) & 0xFF; - c = (temp >> 8) & 0xFF; - d = (temp >> 0) & 0xFF; + int a = (temp >> 24) & 0xFF; + int b = (temp >> 16) & 0xFF; + int c = (temp >> 8) & 0xFF; + int d = (temp >> 0) & 0xFF; temp = D0[Sbox[a]]; temp ^= D1[Sbox[b]]; temp ^= D2[Sbox[c]]; @@ -579,13 +582,15 @@ const unsigned char* src, int len, CRYPT_aes_context* ctx) { - unsigned int iv[4], x[4], ct[4]; + unsigned int iv[4]; + unsigned int x[4]; + unsigned int ct[4]; int i; - ASSERT((len & 15) == 0); + DCHECK_EQ((len & 15), 0); memcpy(iv, ctx->iv, sizeof(iv)); while (len > 0) { for (i = 0; i < 4; i++) { - x[i] = ct[i] = GET_32BIT_MSB_FIRST(src + 4 * i); + x[i] = ct[i] = FXSYS_UINT32_GET_MSBFIRST(src + 4 * i); } aes_decrypt(ctx, x); for (i = 0; i < 4; i++) { @@ -609,11 +614,11 @@ CRYPT_aes_context* ctx) { unsigned int iv[4]; int i; - ASSERT((len & 15) == 0); + DCHECK_EQ((len & 15), 0); memcpy(iv, ctx->iv, sizeof(iv)); while (len > 0) { for (i = 0; i < 4; i++) { - iv[i] ^= GET_32BIT_MSB_FIRST(src + 4 * i); + iv[i] ^= FXSYS_UINT32_GET_MSBFIRST(src + 4 * i); } aes_encrypt(ctx, iv); for (i = 0; i < 4; i++) { @@ -630,14 +635,13 @@ void CRYPT_AESSetKey(CRYPT_aes_context* context, const uint8_t* key, - uint32_t keylen, - bool bEncrypt) { + uint32_t keylen) { aes_setup(context, key, keylen); } void CRYPT_AESSetIV(CRYPT_aes_context* context, const uint8_t* iv) { for (int i = 0; i < context->Nb; i++) - context->iv[i] = GET_32BIT_MSB_FIRST(iv + 4 * i); + context->iv[i] = FXSYS_UINT32_GET_MSBFIRST(iv + 4 * i); } void CRYPT_AESDecrypt(CRYPT_aes_context* context,
diff --git a/core/fdrm/fx_crypt_sha.cpp b/core/fdrm/fx_crypt_sha.cpp index 0371685..b0dc8b5 100644 --- a/core/fdrm/fx_crypt_sha.cpp +++ b/core/fdrm/fx_crypt_sha.cpp
@@ -1,4 +1,4 @@ -// Copyright 2014 PDFium Authors. All rights reserved. +// Copyright 2014 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -6,6 +6,8 @@ #include "core/fdrm/fx_crypt.h" +#include <string.h> + #define SHA_GET_UINT32(n, b, i) \ { \ (n) = ((uint32_t)(b)[(i)] << 24) | ((uint32_t)(b)[(i) + 1] << 16) | \ @@ -48,12 +50,12 @@ (SHA384_ROTR(x, 28) ^ SHA384_ROTR(x, 34) ^ SHA384_ROTR(x, 39)) #define SHA384_S3(x) \ (SHA384_ROTR(x, 14) ^ SHA384_ROTR(x, 18) ^ SHA384_ROTR(x, 41)) -#define SHA384_P(a, b, c, d, e, f, g, h, x, K) \ - { \ - temp1 = h + SHA384_S3(e) + SHA384_F1(e, f, g) + K + x; \ - temp2 = SHA384_S2(a) + SHA384_F0(a, b, c); \ - d += temp1; \ - h = temp1 + temp2; \ +#define SHA384_P(a, b, c, d, e, f, g, h, x, K) \ + { \ + uint64_t temp1 = h + SHA384_S3(e) + SHA384_F1(e, f, g) + K + x; \ + uint64_t temp2 = SHA384_S2(a) + SHA384_F0(a, b, c); \ + d += temp1; \ + h = temp1 + temp2; \ } #define SHA384_R(t) \ (W[t] = SHA384_S1(W[t - 2]) + W[t - 7] + SHA384_S0(W[t - 15]) + W[t - 16]) @@ -68,12 +70,12 @@ #define F0(x, y, z) ((x & y) | (z & (x | y))) #define F1(x, y, z) (z ^ (x & (y ^ z))) #define R(t) (W[t] = S1(W[t - 2]) + W[t - 7] + S0(W[t - 15]) + W[t - 16]) -#define PS(a, b, c, d, e, f, g, h, x, K) \ - { \ - temp1 = h + S3(e) + F1(e, f, g) + K + x; \ - temp2 = S2(a) + F0(a, b, c); \ - d += temp1; \ - h = temp1 + temp2; \ +#define PS(a, b, c, d, e, f, g, h, x, K) \ + { \ + uint32_t temp1 = h + S3(e) + F1(e, f, g) + K + x; \ + uint32_t temp2 = S2(a) + F0(a, b, c); \ + d += temp1; \ + h = temp1 + temp2; \ } namespace { @@ -88,7 +90,6 @@ void SHATransform(unsigned int* digest, unsigned int* block) { unsigned int w[80]; - unsigned int a, b, c, d, e; int t; for (t = 0; t < 16; t++) { w[t] = block[t]; @@ -97,11 +98,11 @@ unsigned int tmp = w[t - 3] ^ w[t - 8] ^ w[t - 14] ^ w[t - 16]; w[t] = rol(tmp, 1); } - a = digest[0]; - b = digest[1]; - c = digest[2]; - d = digest[3]; - e = digest[4]; + unsigned int a = digest[0]; + unsigned int b = digest[1]; + unsigned int c = digest[2]; + unsigned int d = digest[3]; + unsigned int e = digest[4]; for (t = 0; t < 20; t++) { unsigned int tmp = rol(a, 5) + ((b & c) | (d & ~b)) + e + w[t] + 0x5a827999; e = d; @@ -161,16 +162,14 @@ SHA_GET_UINT32(W[14], data, 56); SHA_GET_UINT32(W[15], data, 60); - uint32_t temp1; - uint32_t temp2; - uint32_t A = ctx->state[0]; - uint32_t B = ctx->state[1]; - uint32_t C = ctx->state[2]; - uint32_t D = ctx->state[3]; - uint32_t E = ctx->state[4]; - uint32_t F = ctx->state[5]; - uint32_t G = ctx->state[6]; - uint32_t H = ctx->state[7]; + uint32_t A = static_cast<uint32_t>(ctx->state[0]); + uint32_t B = static_cast<uint32_t>(ctx->state[1]); + uint32_t C = static_cast<uint32_t>(ctx->state[2]); + uint32_t D = static_cast<uint32_t>(ctx->state[3]); + uint32_t E = static_cast<uint32_t>(ctx->state[4]); + uint32_t F = static_cast<uint32_t>(ctx->state[5]); + uint32_t G = static_cast<uint32_t>(ctx->state[6]); + uint32_t H = static_cast<uint32_t>(ctx->state[7]); PS(A, B, C, D, E, F, G, H, W[0], 0x428A2F98); PS(H, A, B, C, D, E, F, G, W[1], 0x71374491); PS(G, H, A, B, C, D, E, F, W[2], 0xB5C0FBCF); @@ -290,8 +289,6 @@ }; void sha384_process(CRYPT_sha2_context* ctx, const uint8_t data[128]) { - uint64_t temp1, temp2; - uint64_t A, B, C, D, E, F, G, H; uint64_t W[80]; SHA_GET_UINT64(W[0], data, 0); SHA_GET_UINT64(W[1], data, 8); @@ -309,14 +306,14 @@ SHA_GET_UINT64(W[13], data, 104); SHA_GET_UINT64(W[14], data, 112); SHA_GET_UINT64(W[15], data, 120); - A = ctx->state[0]; - B = ctx->state[1]; - C = ctx->state[2]; - D = ctx->state[3]; - E = ctx->state[4]; - F = ctx->state[5]; - G = ctx->state[6]; - H = ctx->state[7]; + uint64_t A = ctx->state[0]; + uint64_t B = ctx->state[1]; + uint64_t C = ctx->state[2]; + uint64_t D = ctx->state[3]; + uint64_t E = ctx->state[4]; + uint64_t F = ctx->state[5]; + uint64_t G = ctx->state[6]; + uint64_t H = ctx->state[7]; for (int i = 0; i < 10; ++i) { uint64_t temp[8]; if (i < 2) { @@ -552,7 +549,7 @@ void CRYPT_SHA384Generate(const uint8_t* data, uint32_t size, - uint8_t digest[64]) { + uint8_t digest[48]) { CRYPT_sha2_context context; CRYPT_SHA384Start(&context); CRYPT_SHA384Update(&context, data, size);
diff --git a/core/fdrm/fx_crypt_unittest.cpp b/core/fdrm/fx_crypt_unittest.cpp index de76cd0..f9dd66d 100644 --- a/core/fdrm/fx_crypt_unittest.cpp +++ b/core/fdrm/fx_crypt_unittest.cpp
@@ -1,20 +1,21 @@ -// Copyright (c) 2016 The Chromium Authors. All rights reserved. +// Copyright 2016 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "core/fdrm/fx_crypt.h" -#include <memory> +#include <algorithm> #include <string> +#include <vector> -#include "core/fxcrt/fx_memory.h" #include "testing/gtest/include/gtest/gtest.h" #include "testing/utils/hash.h" namespace { std::string CRYPT_MD5String(const char* str) { - return GenerateMD5Base16(reinterpret_cast<const uint8_t*>(str), strlen(str)); + return GenerateMD5Base16( + {reinterpret_cast<const uint8_t*>(str), strlen(str)}); } void CheckArcFourContext(const CRYPT_rc4_context& context, @@ -23,7 +24,7 @@ const uint8_t* expected_permutation) { EXPECT_EQ(expected_x, context.x); EXPECT_EQ(expected_y, context.y); - for (int32_t i = 0; i < kRC4ContextPermutationLength; ++i) + for (int32_t i = 0; i < CRYPT_rc4_context::kPermutationLength; ++i) EXPECT_EQ(expected_permutation[i], context.m[i]) << i; } @@ -199,7 +200,7 @@ CRYPT_SHA1Generate(reinterpret_cast<const uint8_t*>(kInput), strlen(kInput), actual); - for (size_t i = 0; i < FX_ArraySize(kExpected); i++) + for (size_t i = 0; i < std::size(kExpected); i++) EXPECT_EQ(kExpected[i], actual[i]) << " at byte " << i; } @@ -214,7 +215,7 @@ CRYPT_SHA1Generate(reinterpret_cast<const uint8_t*>(kInput), strlen(kInput), actual); - for (size_t i = 0; i < FX_ArraySize(kExpected); i++) + for (size_t i = 0; i < std::size(kExpected); i++) EXPECT_EQ(kExpected[i], actual[i]) << " at byte " << i; } @@ -230,7 +231,7 @@ CRYPT_SHA1Generate(reinterpret_cast<const uint8_t*>(kInput), strlen(kInput), actual); - for (size_t i = 0; i < FX_ArraySize(kExpected); i++) + for (size_t i = 0; i < std::size(kExpected); i++) EXPECT_EQ(kExpected[i], actual[i]) << " at byte " << i; } @@ -243,7 +244,7 @@ uint8_t actual[32]; CRYPT_SHA256Generate(reinterpret_cast<const uint8_t*>(kInput), strlen(kInput), actual); - for (size_t i = 0; i < FX_ArraySize(kExpected); ++i) + for (size_t i = 0; i < std::size(kExpected); ++i) EXPECT_EQ(kExpected[i], actual[i]) << " at byte " << i; } @@ -257,7 +258,7 @@ uint8_t actual[32]; CRYPT_SHA256Generate(reinterpret_cast<const uint8_t*>(kInput), strlen(kInput), actual); - for (size_t i = 0; i < FX_ArraySize(kExpected); ++i) + for (size_t i = 0; i < std::size(kExpected); ++i) EXPECT_EQ(kExpected[i], actual[i]) << " at byte " << i; } @@ -272,60 +273,64 @@ uint8_t actual[32]; CRYPT_SHA256Generate(reinterpret_cast<const uint8_t*>(kInput), strlen(kInput), actual); - for (size_t i = 0; i < FX_ArraySize(kExpected); ++i) + for (size_t i = 0; i < std::size(kExpected); ++i) EXPECT_EQ(kExpected[i], actual[i]) << " at byte " << i; } TEST(FXCRYPT, CRYPT_ArcFourSetup) { { - static const uint8_t kNullPermutation[kRC4ContextPermutationLength] = { - 0, 35, 3, 43, 9, 11, 65, 229, 32, 36, 134, 98, 59, 34, - 173, 153, 214, 200, 64, 161, 191, 62, 6, 25, 56, 234, 49, 246, - 69, 133, 203, 194, 10, 42, 228, 198, 195, 245, 236, 91, 206, 23, - 235, 27, 138, 18, 143, 250, 244, 76, 123, 217, 132, 249, 72, 127, - 94, 151, 33, 60, 248, 85, 177, 210, 142, 83, 110, 140, 41, 135, - 196, 238, 156, 242, 141, 67, 5, 185, 131, 63, 137, 37, 172, 121, - 70, 144, 237, 130, 17, 44, 253, 166, 78, 201, 12, 119, 215, 7, - 126, 114, 97, 192, 53, 4, 254, 45, 102, 122, 230, 88, 193, 129, - 160, 124, 84, 108, 239, 189, 152, 120, 115, 207, 50, 176, 86, 157, - 164, 187, 71, 1, 15, 58, 29, 21, 46, 145, 247, 162, 95, 183, - 13, 226, 159, 175, 221, 100, 96, 202, 101, 178, 154, 47, 205, 106, - 148, 104, 93, 112, 26, 165, 128, 186, 146, 218, 66, 211, 171, 90, - 252, 19, 40, 99, 223, 174, 255, 51, 77, 227, 48, 220, 168, 118, - 224, 103, 75, 105, 125, 199, 73, 82, 57, 181, 81, 149, 68, 52, - 232, 22, 2, 216, 113, 30, 109, 163, 92, 61, 14, 8, 38, 225, - 79, 231, 170, 240, 20, 219, 204, 150, 180, 188, 116, 190, 241, 197, - 179, 87, 74, 147, 80, 54, 212, 16, 167, 222, 136, 213, 55, 182, - 139, 24, 209, 251, 208, 28, 111, 89, 158, 155, 243, 107, 233, 169, - 117, 184, 31, 39}; + static const uint8_t + kNullPermutation[CRYPT_rc4_context::kPermutationLength] = { + 0, 35, 3, 43, 9, 11, 65, 229, 32, 36, 134, 98, 59, + 34, 173, 153, 214, 200, 64, 161, 191, 62, 6, 25, 56, 234, + 49, 246, 69, 133, 203, 194, 10, 42, 228, 198, 195, 245, 236, + 91, 206, 23, 235, 27, 138, 18, 143, 250, 244, 76, 123, 217, + 132, 249, 72, 127, 94, 151, 33, 60, 248, 85, 177, 210, 142, + 83, 110, 140, 41, 135, 196, 238, 156, 242, 141, 67, 5, 185, + 131, 63, 137, 37, 172, 121, 70, 144, 237, 130, 17, 44, 253, + 166, 78, 201, 12, 119, 215, 7, 126, 114, 97, 192, 53, 4, + 254, 45, 102, 122, 230, 88, 193, 129, 160, 124, 84, 108, 239, + 189, 152, 120, 115, 207, 50, 176, 86, 157, 164, 187, 71, 1, + 15, 58, 29, 21, 46, 145, 247, 162, 95, 183, 13, 226, 159, + 175, 221, 100, 96, 202, 101, 178, 154, 47, 205, 106, 148, 104, + 93, 112, 26, 165, 128, 186, 146, 218, 66, 211, 171, 90, 252, + 19, 40, 99, 223, 174, 255, 51, 77, 227, 48, 220, 168, 118, + 224, 103, 75, 105, 125, 199, 73, 82, 57, 181, 81, 149, 68, + 52, 232, 22, 2, 216, 113, 30, 109, 163, 92, 61, 14, 8, + 38, 225, 79, 231, 170, 240, 20, 219, 204, 150, 180, 188, 116, + 190, 241, 197, 179, 87, 74, 147, 80, 54, 212, 16, 167, 222, + 136, 213, 55, 182, 139, 24, 209, 251, 208, 28, 111, 89, 158, + 155, 243, 107, 233, 169, 117, 184, 31, 39}; CRYPT_rc4_context context; CRYPT_ArcFourSetup(&context, {}); CheckArcFourContext(context, 0, 0, kNullPermutation); } { - static const uint8_t kFoobarPermutation[kRC4ContextPermutationLength] = { - 102, 214, 39, 49, 17, 132, 244, 106, 114, 76, 183, 212, 116, 73, - 42, 103, 128, 246, 139, 199, 31, 234, 25, 109, 48, 19, 121, 4, - 20, 54, 134, 77, 163, 38, 61, 101, 145, 78, 215, 96, 92, 80, - 224, 168, 243, 210, 82, 252, 113, 56, 217, 62, 218, 129, 125, 33, - 99, 9, 153, 59, 43, 13, 206, 124, 131, 18, 213, 118, 173, 122, - 193, 172, 177, 105, 148, 207, 186, 5, 85, 32, 68, 220, 79, 84, - 169, 209, 150, 7, 133, 63, 147, 93, 26, 130, 60, 117, 250, 57, - 24, 247, 200, 127, 136, 66, 112, 107, 140, 154, 70, 170, 185, 138, - 248, 236, 88, 86, 44, 216, 241, 35, 100, 151, 156, 74, 119, 55, - 245, 46, 227, 208, 229, 16, 249, 149, 53, 157, 201, 75, 58, 28, - 142, 238, 182, 180, 179, 144, 12, 6, 176, 10, 90, 239, 104, 40, - 181, 194, 137, 69, 221, 205, 165, 188, 191, 87, 1, 91, 2, 171, - 232, 34, 162, 166, 160, 126, 225, 167, 123, 197, 223, 195, 22, 203, - 189, 237, 37, 27, 222, 175, 23, 143, 152, 192, 21, 231, 228, 141, - 30, 204, 158, 240, 120, 98, 89, 83, 135, 251, 81, 196, 161, 3, - 8, 230, 52, 219, 41, 242, 36, 97, 15, 155, 65, 187, 254, 64, - 159, 67, 211, 108, 178, 146, 202, 11, 164, 226, 184, 50, 190, 174, - 71, 233, 235, 198, 95, 51, 110, 255, 253, 72, 115, 0, 47, 94, - 29, 45, 14, 111}; + static const uint8_t + kFoobarPermutation[CRYPT_rc4_context::kPermutationLength] = { + 102, 214, 39, 49, 17, 132, 244, 106, 114, 76, 183, 212, 116, + 73, 42, 103, 128, 246, 139, 199, 31, 234, 25, 109, 48, 19, + 121, 4, 20, 54, 134, 77, 163, 38, 61, 101, 145, 78, 215, + 96, 92, 80, 224, 168, 243, 210, 82, 252, 113, 56, 217, 62, + 218, 129, 125, 33, 99, 9, 153, 59, 43, 13, 206, 124, 131, + 18, 213, 118, 173, 122, 193, 172, 177, 105, 148, 207, 186, 5, + 85, 32, 68, 220, 79, 84, 169, 209, 150, 7, 133, 63, 147, + 93, 26, 130, 60, 117, 250, 57, 24, 247, 200, 127, 136, 66, + 112, 107, 140, 154, 70, 170, 185, 138, 248, 236, 88, 86, 44, + 216, 241, 35, 100, 151, 156, 74, 119, 55, 245, 46, 227, 208, + 229, 16, 249, 149, 53, 157, 201, 75, 58, 28, 142, 238, 182, + 180, 179, 144, 12, 6, 176, 10, 90, 239, 104, 40, 181, 194, + 137, 69, 221, 205, 165, 188, 191, 87, 1, 91, 2, 171, 232, + 34, 162, 166, 160, 126, 225, 167, 123, 197, 223, 195, 22, 203, + 189, 237, 37, 27, 222, 175, 23, 143, 152, 192, 21, 231, 228, + 141, 30, 204, 158, 240, 120, 98, 89, 83, 135, 251, 81, 196, + 161, 3, 8, 230, 52, 219, 41, 242, 36, 97, 15, 155, 65, + 187, 254, 64, 159, 67, 211, 108, 178, 146, 202, 11, 164, 226, + 184, 50, 190, 174, 71, 233, 235, 198, 95, 51, 110, 255, 253, + 72, 115, 0, 47, 94, 29, 45, 14, 111}; CRYPT_rc4_context context; static const uint8_t kFooBar[] = "foobar"; - CRYPT_ArcFourSetup(&context, {kFooBar, FX_ArraySize(kFooBar) - 1}); + CRYPT_ArcFourSetup(&context, {kFooBar, std::size(kFooBar) - 1}); CheckArcFourContext(context, 0, 0, kFoobarPermutation); } } @@ -343,21 +348,21 @@ CRYPT_rc4_context context; CRYPT_ArcFourSetup(&context, {}); - uint8_t data_short[FX_ArraySize(kDataShort)]; - memcpy(data_short, kDataShort, FX_ArraySize(kDataShort)); + uint8_t data_short[std::size(kDataShort)]; + memcpy(data_short, kDataShort, std::size(kDataShort)); static const uint8_t kExpectedEncryptedDataShort[] = { 138, 112, 236, 97, 242, 66, 52, 89, 225, 38, 88, 8, 47, 78, 216, 24, 170, 106, 26, 199, 208, 131, 157, 242, 55, 11, 25, 90, 66, 182, 19, 255, 210, 181, 85, 69, 31, 240, 206, 171, 97, 62, 202, 172, 30, 252}; static_assert( - FX_ArraySize(kExpectedEncryptedDataShort) == FX_ArraySize(data_short), + std::size(kExpectedEncryptedDataShort) == std::size(data_short), "data_short mismatch"); CRYPT_ArcFourCrypt(&context, data_short); - for (size_t i = 0; i < FX_ArraySize(data_short); ++i) + for (size_t i = 0; i < std::size(data_short); ++i) EXPECT_EQ(kExpectedEncryptedDataShort[i], data_short[i]) << i; - static const uint8_t kPermutation[kRC4ContextPermutationLength] = { + static const uint8_t kPermutation[CRYPT_rc4_context::kPermutationLength] = { 0, 198, 10, 37, 253, 192, 171, 183, 99, 8, 144, 103, 208, 191, 149, 9, 228, 243, 94, 150, 169, 151, 210, 206, 221, 235, 32, 186, 212, 122, 72, 200, 236, 138, 244, 217, 158, 213, 139, 242, 17, 143, @@ -383,8 +388,8 @@ CRYPT_rc4_context context; CRYPT_ArcFourSetup(&context, {}); - uint8_t data_long[FX_ArraySize(kDataLong)]; - memcpy(data_long, kDataLong, FX_ArraySize(kDataLong)); + uint8_t data_long[std::size(kDataLong)]; + memcpy(data_long, kDataLong, std::size(kDataLong)); static const uint8_t kExpectedEncryptedDataLong[] = { 138, 112, 236, 97, 242, 66, 52, 89, 225, 38, 88, 8, 47, 78, 216, 24, 170, 106, 26, 199, 208, 131, 157, 242, 55, 11, 25, 90, @@ -406,15 +411,14 @@ 208, 161, 105, 226, 164, 114, 80, 137, 58, 107, 109, 42, 110, 100, 202, 170, 224, 89, 28, 5, 138, 19, 253, 105, 220, 105, 24, 187, 109, 89, 205, 89, 202}; - static_assert( - FX_ArraySize(kExpectedEncryptedDataLong) == FX_ArraySize(data_long), - "data_long mismatch"); - static_assert(FX_ArraySize(data_long) > 256, "too short"); + static_assert(std::size(kExpectedEncryptedDataLong) == std::size(data_long), + "data_long mismatch"); + static_assert(std::size(data_long) > 256, "too short"); CRYPT_ArcFourCrypt(&context, data_long); - for (size_t i = 0; i < FX_ArraySize(data_long); ++i) + for (size_t i = 0; i < std::size(data_long); ++i) EXPECT_EQ(kExpectedEncryptedDataLong[i], data_long[i]) << i; - static const uint8_t kPermutation[kRC4ContextPermutationLength] = { + static const uint8_t kPermutation[CRYPT_rc4_context::kPermutationLength] = { 172, 59, 196, 72, 101, 21, 215, 210, 212, 52, 243, 73, 47, 213, 211, 50, 228, 144, 66, 93, 169, 31, 237, 206, 221, 235, 222, 250, 97, 87, 174, 164, 190, 111, 27, 217, 173, 189, 65, 11, 115, 171, @@ -439,23 +443,23 @@ { CRYPT_rc4_context context; static const uint8_t kFooBar[] = "foobar"; - CRYPT_ArcFourSetup(&context, {kFooBar, FX_ArraySize(kFooBar) - 1}); + CRYPT_ArcFourSetup(&context, {kFooBar, std::size(kFooBar) - 1}); - uint8_t data_short[FX_ArraySize(kDataShort)]; - memcpy(data_short, kDataShort, FX_ArraySize(kDataShort)); + uint8_t data_short[std::size(kDataShort)]; + memcpy(data_short, kDataShort, std::size(kDataShort)); static const uint8_t kExpectedEncryptedDataShort[] = { 59, 193, 117, 206, 167, 54, 218, 7, 229, 214, 188, 55, 90, 205, 196, 25, 36, 114, 199, 218, 161, 107, 122, 119, 106, 167, 44, 175, 240, 123, 192, 102, 174, 167, 105, 187, 202, 70, 121, 81, 17, 30, 5, 138, 116, 166}; static_assert( - FX_ArraySize(kExpectedEncryptedDataShort) == FX_ArraySize(data_short), + std::size(kExpectedEncryptedDataShort) == std::size(data_short), "data_short mismatch"); CRYPT_ArcFourCrypt(&context, data_short); - for (size_t i = 0; i < FX_ArraySize(data_short); ++i) + for (size_t i = 0; i < std::size(data_short); ++i) EXPECT_EQ(kExpectedEncryptedDataShort[i], data_short[i]) << i; - static const uint8_t kPermutation[kRC4ContextPermutationLength] = { + static const uint8_t kPermutation[CRYPT_rc4_context::kPermutationLength] = { 102, 41, 45, 82, 124, 141, 237, 38, 6, 64, 90, 140, 254, 96, 220, 109, 99, 49, 27, 227, 205, 75, 191, 37, 17, 54, 83, 196, 108, 79, 31, 190, 180, 0, 125, 194, 243, 156, 224, 246, 253, 193, @@ -480,10 +484,10 @@ { CRYPT_rc4_context context; static const uint8_t kFooBar[] = "foobar"; - CRYPT_ArcFourSetup(&context, {kFooBar, FX_ArraySize(kFooBar) - 1}); + CRYPT_ArcFourSetup(&context, {kFooBar, std::size(kFooBar) - 1}); - uint8_t data_long[FX_ArraySize(kDataLong)]; - memcpy(data_long, kDataLong, FX_ArraySize(kDataLong)); + uint8_t data_long[std::size(kDataLong)]; + memcpy(data_long, kDataLong, std::size(kDataLong)); static const uint8_t kExpectedEncryptedDataLong[] = { 59, 193, 117, 206, 167, 54, 218, 7, 229, 214, 188, 55, 90, 205, 196, 25, 36, 114, 199, 218, 161, 107, 122, 119, 106, 167, 44, 175, @@ -505,15 +509,14 @@ 22, 110, 43, 56, 94, 127, 48, 96, 47, 172, 3, 31, 130, 249, 243, 73, 206, 89, 9, 93, 156, 167, 205, 166, 75, 227, 36, 34, 81, 124, 195, 246, 152}; - static_assert( - FX_ArraySize(kExpectedEncryptedDataLong) == FX_ArraySize(data_long), - "data_long mismatch"); - static_assert(FX_ArraySize(data_long) > 256, "too short"); + static_assert(std::size(kExpectedEncryptedDataLong) == std::size(data_long), + "data_long mismatch"); + static_assert(std::size(data_long) > 256, "too short"); CRYPT_ArcFourCrypt(&context, data_long); - for (size_t i = 0; i < FX_ArraySize(data_long); ++i) + for (size_t i = 0; i < std::size(data_long); ++i) EXPECT_EQ(kExpectedEncryptedDataLong[i], data_long[i]) << i; - static const uint8_t kPermutation[kRC4ContextPermutationLength] = { + static const uint8_t kPermutation[CRYPT_rc4_context::kPermutationLength] = { 188, 12, 81, 130, 228, 58, 124, 218, 72, 210, 50, 70, 166, 38, 110, 111, 73, 49, 27, 227, 249, 21, 1, 226, 17, 54, 53, 16, 108, 51, 31, 123, 221, 23, 125, 148, 5, 200, 208, 246, 253, 193, @@ -547,7 +550,7 @@ uint8_t actual[48]; CRYPT_SHA384Generate(reinterpret_cast<const uint8_t*>(kInput), strlen(kInput), actual); - for (size_t i = 0; i < FX_ArraySize(kExpected); ++i) + for (size_t i = 0; i < std::size(kExpected); ++i) EXPECT_EQ(kExpected[i], actual[i]) << " at byte " << i; } @@ -563,7 +566,7 @@ uint8_t actual[48]; CRYPT_SHA384Generate(reinterpret_cast<const uint8_t*>(kInput), strlen(kInput), actual); - for (size_t i = 0; i < FX_ArraySize(kExpected); ++i) + for (size_t i = 0; i < std::size(kExpected); ++i) EXPECT_EQ(kExpected[i], actual[i]) << " at byte " << i; } @@ -581,7 +584,7 @@ EXPECT_EQ(112u, strlen(kInput)); CRYPT_SHA384Generate(reinterpret_cast<const uint8_t*>(kInput), strlen(kInput), actual); - for (size_t i = 0; i < FX_ArraySize(kExpected); ++i) + for (size_t i = 0; i < std::size(kExpected); ++i) EXPECT_EQ(kExpected[i], actual[i]) << " at byte " << i; } @@ -597,7 +600,7 @@ uint8_t actual[64]; CRYPT_SHA512Generate(reinterpret_cast<const uint8_t*>(kInput), strlen(kInput), actual); - for (size_t i = 0; i < FX_ArraySize(kExpected); ++i) + for (size_t i = 0; i < std::size(kExpected); ++i) EXPECT_EQ(kExpected[i], actual[i]) << " at byte " << i; } @@ -615,7 +618,7 @@ uint8_t actual[64]; CRYPT_SHA512Generate(reinterpret_cast<const uint8_t*>(kInput), strlen(kInput), actual); - for (size_t i = 0; i < FX_ArraySize(kExpected); ++i) + for (size_t i = 0; i < std::size(kExpected); ++i) EXPECT_EQ(kExpected[i], actual[i]) << " at byte " << i; } @@ -635,6 +638,6 @@ EXPECT_EQ(112u, strlen(kInput)); CRYPT_SHA512Generate(reinterpret_cast<const uint8_t*>(kInput), strlen(kInput), actual); - for (size_t i = 0; i < FX_ArraySize(kExpected); ++i) + for (size_t i = 0; i < std::size(kExpected); ++i) EXPECT_EQ(kExpected[i], actual[i]) << " at byte " << i; }
diff --git a/core/fpdfapi/cmaps/BUILD.gn b/core/fpdfapi/cmaps/BUILD.gn index e7fddbf..23079c8 100644 --- a/core/fpdfapi/cmaps/BUILD.gn +++ b/core/fpdfapi/cmaps/BUILD.gn
@@ -1,4 +1,4 @@ -# Copyright 2018 The PDFium Authors. All rights reserved. +# Copyright 2018 The PDFium Authors # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. @@ -70,7 +70,10 @@ "fpdf_cmaps.cpp", "fpdf_cmaps.h", ] - configs += [ "../../../:pdfium_core_config" ] + configs += [ + "../../../:pdfium_strict_config", + "../../../:pdfium_noshorten_config", + ] deps = [ "../../fxcrt" ] visibility = [ "../../../*" ] }
diff --git a/core/fpdfapi/cmaps/CNS1/Adobe-CNS1-UCS2_5.cpp b/core/fpdfapi/cmaps/CNS1/Adobe-CNS1-UCS2_5.cpp index c904239..154233b 100644 --- a/core/fpdfapi/cmaps/CNS1/Adobe-CNS1-UCS2_5.cpp +++ b/core/fpdfapi/cmaps/CNS1/Adobe-CNS1-UCS2_5.cpp
@@ -1,4 +1,4 @@ -// Copyright 2014 PDFium Authors. All rights reserved. +// Copyright 2014 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -6,7 +6,9 @@ #include "core/fpdfapi/cmaps/CNS1/cmaps_cns1.h" -const uint16_t g_FXCMAP_CNS1CID2Unicode_5[19088] = { +namespace fxcmap { + +const uint16_t kCNS1CID2Unicode_5[19088] = { 0xFFFD, 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, 0x0028, 0x0029, 0x002A, 0x002B, 0x002C, 0x002D, 0x002E, 0x002F, 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, 0x0038, 0x0039, @@ -2129,3 +2131,5 @@ 0x0000, 0x0000, 0x456D, 0x38D4, 0x0000, 0x4561, 0x451B, 0x4D89, 0x4C7B, 0x4D76, 0x45EA, 0x3FC8, 0x0000, 0x3661, 0x44DE, 0x44BD, 0x41ED, }; + +} // namespace fxcmap
diff --git a/core/fpdfapi/cmaps/CNS1/B5pc-H_0.cpp b/core/fpdfapi/cmaps/CNS1/B5pc-H_0.cpp index 0c96065..d24620c 100644 --- a/core/fpdfapi/cmaps/CNS1/B5pc-H_0.cpp +++ b/core/fpdfapi/cmaps/CNS1/B5pc-H_0.cpp
@@ -1,4 +1,4 @@ -// Copyright 2014 PDFium Authors. All rights reserved. +// Copyright 2014 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -6,7 +6,9 @@ #include "core/fpdfapi/cmaps/CNS1/cmaps_cns1.h" -const uint16_t g_FXCMAP_B5pc_H_0[247 * 3] = { +namespace fxcmap { + +const uint16_t kB5pc_H_0[247 * 3] = { 0x0020, 0x007E, 0x0001, 0x0080, 0x0080, 0x003D, 0x00FD, 0x00FF, 0x0060, 0xA140, 0xA158, 0x0063, 0xA159, 0xA15C, 0x35AF, 0xA15D, 0xA17E, 0x0080, 0xA1A1, 0xA1F5, 0x00A2, 0xA1F6, 0xA1F6, 0x00F8, 0xA1F7, 0xA1F7, 0x00F7, @@ -91,3 +93,5 @@ 0xF9C5, 0xF9C5, 0x353D, 0xF9C6, 0xF9C6, 0x3549, 0xF9C7, 0xF9D1, 0x353E, 0xF9D2, 0xF9D5, 0x354A, }; + +} // namespace fxcmap
diff --git a/core/fpdfapi/cmaps/CNS1/B5pc-V_0.cpp b/core/fpdfapi/cmaps/CNS1/B5pc-V_0.cpp index 88768d6..b7a17a5 100644 --- a/core/fpdfapi/cmaps/CNS1/B5pc-V_0.cpp +++ b/core/fpdfapi/cmaps/CNS1/B5pc-V_0.cpp
@@ -1,4 +1,4 @@ -// Copyright 2014 PDFium Authors. All rights reserved. +// Copyright 2014 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -6,9 +6,13 @@ #include "core/fpdfapi/cmaps/CNS1/cmaps_cns1.h" -const uint16_t g_FXCMAP_B5pc_V_0[12 * 3] = { +namespace fxcmap { + +const uint16_t kB5pc_V_0[12 * 3] = { 0xA14B, 0xA14B, 0x354E, 0xA15A, 0xA15A, 0x35AF, 0xA15C, 0xA15C, 0x35B1, 0xA15D, 0xA15E, 0x0082, 0xA161, 0xA162, 0x0086, 0xA165, 0xA166, 0x008A, 0xA169, 0xA16A, 0x008E, 0xA16D, 0xA16E, 0x0092, 0xA171, 0xA172, 0x0096, 0xA175, 0xA176, 0x009A, 0xA179, 0xA17A, 0x009E, 0xA1E3, 0xA1E3, 0x354F, }; + +} // namespace fxcmap
diff --git a/core/fpdfapi/cmaps/CNS1/CNS-EUC-H_0.cpp b/core/fpdfapi/cmaps/CNS1/CNS-EUC-H_0.cpp index 9d0cee8..cfa4eac 100644 --- a/core/fpdfapi/cmaps/CNS1/CNS-EUC-H_0.cpp +++ b/core/fpdfapi/cmaps/CNS1/CNS-EUC-H_0.cpp
@@ -1,4 +1,4 @@ -// Copyright 2014 PDFium Authors. All rights reserved. +// Copyright 2014 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -6,7 +6,9 @@ #include "core/fpdfapi/cmaps/CNS1/cmaps_cns1.h" -const uint16_t g_FXCMAP_CNS_EUC_H_0[157 * 3] = { +namespace fxcmap { + +const uint16_t kCNS_EUC_H_0[157 * 3] = { 0x0020, 0x007E, 0x3550, 0xA1A1, 0xA1FE, 0x0063, 0xA2A1, 0xA2FE, 0x00C1, 0xA3A1, 0xA3CE, 0x011F, 0xA4A1, 0xA4FE, 0x014D, 0xA5A1, 0xA5EC, 0x01AB, 0xA5EE, 0xA5F0, 0x01F7, 0xA6A1, 0xA6BE, 0x01FA, 0xA7A1, 0xA7A1, 0x0253, @@ -62,7 +64,7 @@ 0xFDA1, 0xFDCB, 0x1741, }; -const FXCMAP_DWordCIDMap g_FXCMAP_CNS_EUC_H_0_DWord[238] = { +const DWordCIDMap kCNS_EUC_H_0_DWord[238] = { {0x8EA1, 0xA1A1, 0xA1FE, 0x0063}, {0x8EA1, 0xA2A1, 0xA2FE, 0x00C1}, {0x8EA1, 0xA3A1, 0xA3CE, 0x011F}, {0x8EA1, 0xA4A1, 0xA4FE, 0x014D}, {0x8EA1, 0xA5A1, 0xA5EC, 0x01AB}, {0x8EA1, 0xA5EE, 0xA5F0, 0x01F7}, @@ -183,3 +185,5 @@ {0x8EA2, 0xEFA1, 0xEFFE, 0x3410}, {0x8EA2, 0xF0A1, 0xF0FE, 0x346E}, {0x8EA2, 0xF1A1, 0xF1FE, 0x34CC}, {0x8EA2, 0xF2A1, 0xF2C4, 0x352A}, }; + +} // namespace fxcmap
diff --git a/core/fpdfapi/cmaps/CNS1/CNS-EUC-V_0.cpp b/core/fpdfapi/cmaps/CNS1/CNS-EUC-V_0.cpp index 1698106..97834d9 100644 --- a/core/fpdfapi/cmaps/CNS1/CNS-EUC-V_0.cpp +++ b/core/fpdfapi/cmaps/CNS1/CNS-EUC-V_0.cpp
@@ -1,4 +1,4 @@ -// Copyright 2014 PDFium Authors. All rights reserved. +// Copyright 2014 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -6,7 +6,9 @@ #include "core/fpdfapi/cmaps/CNS1/cmaps_cns1.h" -const uint16_t g_FXCMAP_CNS_EUC_V_0[180 * 3] = { +namespace fxcmap { + +const uint16_t kCNS_EUC_V_0[180 * 3] = { 0x0020, 0x007E, 0x3550, 0xA1A1, 0xA1AB, 0x0063, 0xA1AC, 0xA1AC, 0x354E, 0xA1AD, 0xA1BA, 0x006F, 0xA1BB, 0xA1BB, 0x007C, 0xA1BC, 0xA1BC, 0x007E, 0xA1BD, 0xA1BD, 0x007E, 0xA1BE, 0xA1BF, 0x0082, 0xA1C0, 0xA1C1, 0x0082, @@ -69,7 +71,7 @@ 0xFBA1, 0xFBFE, 0x1685, 0xFCA1, 0xFCFE, 0x16E3, 0xFDA1, 0xFDCB, 0x1741, }; -const FXCMAP_DWordCIDMap g_FXCMAP_CNS_EUC_V_0_DWord[261] = { +const DWordCIDMap kCNS_EUC_V_0_DWord[261] = { {0x8EA1, 0xA1A1, 0xA1AB, 0x0063}, {0x8EA1, 0xA1AC, 0xA1AC, 0x354E}, {0x8EA1, 0xA1AD, 0xA1BA, 0x006F}, {0x8EA1, 0xA1BB, 0xA1BB, 0x007C}, {0x8EA1, 0xA1BC, 0xA1BC, 0x007E}, {0x8EA1, 0xA1BD, 0xA1BD, 0x007E}, @@ -202,3 +204,5 @@ {0x8EA2, 0xF0A1, 0xF0FE, 0x346E}, {0x8EA2, 0xF1A1, 0xF1FE, 0x34CC}, {0x8EA2, 0xF2A1, 0xF2C4, 0x352A}, }; + +} // namespace fxcmap
diff --git a/core/fpdfapi/cmaps/CNS1/ETen-B5-H_0.cpp b/core/fpdfapi/cmaps/CNS1/ETen-B5-H_0.cpp index 3138ae9..44687c1 100644 --- a/core/fpdfapi/cmaps/CNS1/ETen-B5-H_0.cpp +++ b/core/fpdfapi/cmaps/CNS1/ETen-B5-H_0.cpp
@@ -1,4 +1,4 @@ -// Copyright 2014 PDFium Authors. All rights reserved. +// Copyright 2014 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -6,7 +6,9 @@ #include "core/fpdfapi/cmaps/CNS1/cmaps_cns1.h" -const uint16_t g_FXCMAP_ETen_B5_H_0[254 * 3] = { +namespace fxcmap { + +const uint16_t kETen_B5_H_0[254 * 3] = { 0x0020, 0x007E, 0x3550, 0xA140, 0xA158, 0x0063, 0xA159, 0xA15C, 0x35AF, 0xA15D, 0xA17E, 0x0080, 0xA1A1, 0xA1F5, 0x00A2, 0xA1F6, 0xA1F6, 0x00F8, 0xA1F7, 0xA1F7, 0x00F7, 0xA1F8, 0xA1FE, 0x00F9, 0xA240, 0xA27E, 0x0100, @@ -93,3 +95,5 @@ 0xF9C5, 0xF9C5, 0x353D, 0xF9C6, 0xF9C6, 0x3549, 0xF9C7, 0xF9D1, 0x353E, 0xF9D2, 0xF9D5, 0x354A, 0xF9D6, 0xF9FE, 0x36E8, }; + +} // namespace fxcmap
diff --git a/core/fpdfapi/cmaps/CNS1/ETen-B5-V_0.cpp b/core/fpdfapi/cmaps/CNS1/ETen-B5-V_0.cpp index 622f2ff..38359e8 100644 --- a/core/fpdfapi/cmaps/CNS1/ETen-B5-V_0.cpp +++ b/core/fpdfapi/cmaps/CNS1/ETen-B5-V_0.cpp
@@ -1,4 +1,4 @@ -// Copyright 2014 PDFium Authors. All rights reserved. +// Copyright 2014 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -6,10 +6,14 @@ #include "core/fpdfapi/cmaps/CNS1/cmaps_cns1.h" -const uint16_t g_FXCMAP_ETen_B5_V_0[13 * 3] = { +namespace fxcmap { + +const uint16_t kETen_B5_V_0[13 * 3] = { 0xA14B, 0xA14B, 0x354E, 0xA15A, 0xA15A, 0x35AF, 0xA15C, 0xA15C, 0x35B1, 0xA15D, 0xA15E, 0x0082, 0xA161, 0xA162, 0x0086, 0xA165, 0xA166, 0x008A, 0xA169, 0xA16A, 0x008E, 0xA16D, 0xA16E, 0x0092, 0xA171, 0xA172, 0x0096, 0xA175, 0xA176, 0x009A, 0xA179, 0xA17A, 0x009E, 0xA1E3, 0xA1E3, 0x354F, 0xC6E4, 0xC6E5, 0x3711, }; + +} // namespace fxcmap
diff --git a/core/fpdfapi/cmaps/CNS1/ETenms-B5-H_0.cpp b/core/fpdfapi/cmaps/CNS1/ETenms-B5-H_0.cpp index 3cc5573..0f44566 100644 --- a/core/fpdfapi/cmaps/CNS1/ETenms-B5-H_0.cpp +++ b/core/fpdfapi/cmaps/CNS1/ETenms-B5-H_0.cpp
@@ -1,4 +1,4 @@ -// Copyright 2014 PDFium Authors. All rights reserved. +// Copyright 2014 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -6,8 +6,12 @@ #include "core/fpdfapi/cmaps/CNS1/cmaps_cns1.h" -const uint16_t g_FXCMAP_ETenms_B5_H_0[1 * 3] = { +namespace fxcmap { + +const uint16_t kETenms_B5_H_0[1 * 3] = { 0x0020, 0x007E, 0x0001, }; + +} // namespace fxcmap
diff --git a/core/fpdfapi/cmaps/CNS1/ETenms-B5-V_0.cpp b/core/fpdfapi/cmaps/CNS1/ETenms-B5-V_0.cpp index de92249..5aafd16 100644 --- a/core/fpdfapi/cmaps/CNS1/ETenms-B5-V_0.cpp +++ b/core/fpdfapi/cmaps/CNS1/ETenms-B5-V_0.cpp
@@ -1,4 +1,4 @@ -// Copyright 2014 PDFium Authors. All rights reserved. +// Copyright 2014 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -6,7 +6,9 @@ #include "core/fpdfapi/cmaps/CNS1/cmaps_cns1.h" -const uint16_t g_FXCMAP_ETenms_B5_V_0[18 * 3] = { +namespace fxcmap { + +const uint16_t kETenms_B5_V_0[18 * 3] = { 0xA14B, 0xA14B, 0x354E, 0xA14C, 0xA14C, 0x006D, 0xA156, 0xA156, 0x0138, 0xA158, 0xA158, 0x007A, 0xA15A, 0xA15A, 0x35AF, 0xA15C, 0xA15C, 0x35B1, 0xA15D, 0xA15E, 0x0082, 0xA161, 0xA162, 0x0086, 0xA165, 0xA166, 0x008A, @@ -14,3 +16,5 @@ 0xA175, 0xA176, 0x009A, 0xA179, 0xA17A, 0x009E, 0xA17D, 0xA17E, 0x0082, 0xA1A1, 0xA1A2, 0x0086, 0xA1A3, 0xA1A4, 0x008A, 0xC6E4, 0xC6E5, 0x3711, }; + +} // namespace fxcmap
diff --git a/core/fpdfapi/cmaps/CNS1/HKscs-B5-H_5.cpp b/core/fpdfapi/cmaps/CNS1/HKscs-B5-H_5.cpp index 47f7d6a..e073f3e 100644 --- a/core/fpdfapi/cmaps/CNS1/HKscs-B5-H_5.cpp +++ b/core/fpdfapi/cmaps/CNS1/HKscs-B5-H_5.cpp
@@ -1,4 +1,4 @@ -// Copyright 2014 PDFium Authors. All rights reserved. +// Copyright 2014 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -6,7 +6,9 @@ #include "core/fpdfapi/cmaps/CNS1/cmaps_cns1.h" -const uint16_t g_FXCMAP_HKscs_B5_H_5[1210 * 3] = { +namespace fxcmap { + +const uint16_t kHKscs_B5_H_5[1210 * 3] = { 0x0020, 0x007E, 0x0001, 0x8740, 0x8765, 0x4A15, 0x8767, 0x8779, 0x4A3B, 0x8840, 0x8855, 0x44C9, 0x8856, 0x887E, 0x4961, 0x88A1, 0x88A8, 0x498A, 0x88A9, 0x88AA, 0x499C, 0x8940, 0x8941, 0x4534, 0x8943, 0x8943, 0x4536, @@ -412,3 +414,5 @@ 0xFEDE, 0xFEDF, 0x495D, 0xFEE0, 0xFEEC, 0x42EB, 0xFEED, 0xFEEE, 0x495F, 0xFEEF, 0xFEFE, 0x42F8, }; + +} // namespace fxcmap
diff --git a/core/fpdfapi/cmaps/CNS1/HKscs-B5-V_5.cpp b/core/fpdfapi/cmaps/CNS1/HKscs-B5-V_5.cpp index a833497..ab6418c 100644 --- a/core/fpdfapi/cmaps/CNS1/HKscs-B5-V_5.cpp +++ b/core/fpdfapi/cmaps/CNS1/HKscs-B5-V_5.cpp
@@ -1,4 +1,4 @@ -// Copyright 2014 PDFium Authors. All rights reserved. +// Copyright 2014 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -6,10 +6,14 @@ #include "core/fpdfapi/cmaps/CNS1/cmaps_cns1.h" -const uint16_t g_FXCMAP_HKscs_B5_V_5[13 * 3] = { +namespace fxcmap { + +const uint16_t kHKscs_B5_V_5[13 * 3] = { 0xA14B, 0xA14B, 0x354E, 0xA15A, 0xA15A, 0x35AF, 0xA15C, 0xA15C, 0x35B1, 0xA15D, 0xA15E, 0x0082, 0xA161, 0xA162, 0x0086, 0xA165, 0xA166, 0x008A, 0xA169, 0xA16A, 0x008E, 0xA16D, 0xA16E, 0x0092, 0xA171, 0xA172, 0x0096, 0xA175, 0xA176, 0x009A, 0xA179, 0xA17A, 0x009E, 0xA1E3, 0xA1E3, 0x354F, 0xC6E4, 0xC6E5, 0x3711, }; + +} // namespace fxcmap
diff --git a/core/fpdfapi/cmaps/CNS1/UniCNS-UCS2-H_3.cpp b/core/fpdfapi/cmaps/CNS1/UniCNS-UCS2-H_3.cpp index bfe6a34..fb13a37 100644 --- a/core/fpdfapi/cmaps/CNS1/UniCNS-UCS2-H_3.cpp +++ b/core/fpdfapi/cmaps/CNS1/UniCNS-UCS2-H_3.cpp
@@ -1,4 +1,4 @@ -// Copyright 2014 PDFium Authors. All rights reserved. +// Copyright 2014 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -6,7 +6,9 @@ #include "core/fpdfapi/cmaps/CNS1/cmaps_cns1.h" -const uint16_t g_FXCMAP_UniCNS_UCS2_H_3[16418 * 3] = { +namespace fxcmap { + +const uint16_t kUniCNS_UCS2_H_3[16418 * 3] = { 0x0020, 0x007E, 0x0001, 0x00A2, 0x00A3, 0x0106, 0x00A5, 0x00A5, 0x0104, 0x00A7, 0x00A7, 0x00B2, 0x00A8, 0x00A8, 0x35B3, 0x00AC, 0x00AC, 0x36E1, 0x00B0, 0x00B0, 0x0118, 0x00B1, 0x00B1, 0x00D4, 0x00B7, 0x00B7, 0x0073, @@ -5481,3 +5483,5 @@ 0xFF5C, 0xFF5C, 0x0078, 0xFF5D, 0xFF5D, 0x0085, 0xFF64, 0xFF64, 0x0071, 0xFFE2, 0xFFE2, 0x36E1, 0xFFE4, 0xFFE4, 0x36E2, }; + +} // namespace fxcmap
diff --git a/core/fpdfapi/cmaps/CNS1/UniCNS-UCS2-V_3.cpp b/core/fpdfapi/cmaps/CNS1/UniCNS-UCS2-V_3.cpp index dfa7b87..36cb2a6 100644 --- a/core/fpdfapi/cmaps/CNS1/UniCNS-UCS2-V_3.cpp +++ b/core/fpdfapi/cmaps/CNS1/UniCNS-UCS2-V_3.cpp
@@ -1,4 +1,4 @@ -// Copyright 2014 PDFium Authors. All rights reserved. +// Copyright 2014 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -6,10 +6,14 @@ #include "core/fpdfapi/cmaps/CNS1/cmaps_cns1.h" -const uint16_t g_FXCMAP_UniCNS_UCS2_V_3[13 * 3] = { +namespace fxcmap { + +const uint16_t kUniCNS_UCS2_V_3[13 * 3] = { 0x2013, 0x2013, 0x0078, 0x2014, 0x2014, 0x007A, 0x2025, 0x2025, 0x006D, 0x3008, 0x3009, 0x0096, 0x300A, 0x300B, 0x0092, 0x300C, 0x300D, 0x009A, 0x300E, 0x300F, 0x009E, 0x3010, 0x3011, 0x008E, 0x3014, 0x3015, 0x008A, 0xFE4F, 0xFE4F, 0x35B1, 0xFF08, 0xFF09, 0x0082, 0xFF5B, 0xFF5B, 0x0086, 0xFF5D, 0xFF5D, 0x0087, }; + +} // namespace fxcmap
diff --git a/core/fpdfapi/cmaps/CNS1/UniCNS-UTF16-H_0.cpp b/core/fpdfapi/cmaps/CNS1/UniCNS-UTF16-H_0.cpp index a033c13..05fc715 100644 --- a/core/fpdfapi/cmaps/CNS1/UniCNS-UTF16-H_0.cpp +++ b/core/fpdfapi/cmaps/CNS1/UniCNS-UTF16-H_0.cpp
@@ -1,4 +1,4 @@ -// Copyright 2014 PDFium Authors. All rights reserved. +// Copyright 2014 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -6,7 +6,9 @@ #include "core/fpdfapi/cmaps/CNS1/cmaps_cns1.h" -const uint16_t g_FXCMAP_UniCNS_UTF16_H_0[14557 * 2] = { +namespace fxcmap { + +const uint16_t kUniCNS_UTF16_H_0[14557 * 2] = { 0x0020, 0x0001, 0x0021, 0x0002, 0x0022, 0x0003, 0x0023, 0x0004, 0x0024, 0x0005, 0x0025, 0x0006, 0x0026, 0x0007, 0x0027, 0x0008, 0x0028, 0x0009, 0x0029, 0x000A, 0x002A, 0x000B, 0x002B, 0x000C, 0x002C, 0x000D, 0x002D, @@ -3243,3 +3245,5 @@ 0x0085, 0xFF5E, 0x00E4, 0xFF64, 0x0071, 0xFFE0, 0x0106, 0xFFE1, 0x0107, 0xFFE2, 0x36E1, 0xFFE3, 0x00C4, 0xFFE4, 0x36E2, 0xFFE5, 0x0104, }; + +} // namespace fxcmap
diff --git a/core/fpdfapi/cmaps/CNS1/cmaps_cns1.cpp b/core/fpdfapi/cmaps/CNS1/cmaps_cns1.cpp index 810104e..18a1970 100644 --- a/core/fpdfapi/cmaps/CNS1/cmaps_cns1.cpp +++ b/core/fpdfapi/cmaps/CNS1/cmaps_cns1.cpp
@@ -1,4 +1,4 @@ -// Copyright 2014 PDFium Authors. All rights reserved. +// Copyright 2014 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -6,33 +6,32 @@ #include "core/fpdfapi/cmaps/CNS1/cmaps_cns1.h" -#include "core/fxcrt/fx_memory.h" +#include <iterator> -const FXCMAP_CMap g_FXCMAP_CNS1_cmaps[] = { - {"B5pc-H", g_FXCMAP_B5pc_H_0, nullptr, 247, 0, FXCMAP_CMap::Range, 0}, - {"B5pc-V", g_FXCMAP_B5pc_V_0, nullptr, 12, 0, FXCMAP_CMap::Range, -1}, - {"HKscs-B5-H", g_FXCMAP_HKscs_B5_H_5, nullptr, 1210, 0, FXCMAP_CMap::Range, +namespace fxcmap { + +const CMap kCNS1_cmaps[] = { + {"B5pc-H", kB5pc_H_0, nullptr, 247, 0, CMap::Type::kRange, 0}, + {"B5pc-V", kB5pc_V_0, nullptr, 12, 0, CMap::Type::kRange, -1}, + {"HKscs-B5-H", kHKscs_B5_H_5, nullptr, 1210, 0, CMap::Type::kRange, 0}, + {"HKscs-B5-V", kHKscs_B5_V_5, nullptr, 13, 0, CMap::Type::kRange, -1}, + {"ETen-B5-H", kETen_B5_H_0, nullptr, 254, 0, CMap::Type::kRange, 0}, + {"ETen-B5-V", kETen_B5_V_0, nullptr, 13, 0, CMap::Type::kRange, -1}, + {"ETenms-B5-H", kETenms_B5_H_0, nullptr, 1, 0, CMap::Type::kRange, -2}, + {"ETenms-B5-V", kETenms_B5_V_0, nullptr, 18, 0, CMap::Type::kRange, -1}, + {"CNS-EUC-H", kCNS_EUC_H_0, kCNS_EUC_H_0_DWord, 157, 238, + CMap::Type::kRange, 0}, + {"CNS-EUC-V", kCNS_EUC_V_0, kCNS_EUC_V_0_DWord, 180, 261, + CMap::Type::kRange, 0}, + {"UniCNS-UCS2-H", kUniCNS_UCS2_H_3, nullptr, 16418, 0, CMap::Type::kRange, 0}, - {"HKscs-B5-V", g_FXCMAP_HKscs_B5_V_5, nullptr, 13, 0, FXCMAP_CMap::Range, + {"UniCNS-UCS2-V", kUniCNS_UCS2_V_3, nullptr, 13, 0, CMap::Type::kRange, -1}, + {"UniCNS-UTF16-H", kUniCNS_UTF16_H_0, nullptr, 14557, 0, + CMap::Type::kSingle, 0}, + {"UniCNS-UTF16-V", kUniCNS_UCS2_V_3, nullptr, 13, 0, CMap::Type::kRange, -1}, - {"ETen-B5-H", g_FXCMAP_ETen_B5_H_0, nullptr, 254, 0, FXCMAP_CMap::Range, 0}, - {"ETen-B5-V", g_FXCMAP_ETen_B5_V_0, nullptr, 13, 0, FXCMAP_CMap::Range, -1}, - {"ETenms-B5-H", g_FXCMAP_ETenms_B5_H_0, nullptr, 1, 0, FXCMAP_CMap::Range, - -2}, - {"ETenms-B5-V", g_FXCMAP_ETenms_B5_V_0, nullptr, 18, 0, FXCMAP_CMap::Range, - -1}, - {"CNS-EUC-H", g_FXCMAP_CNS_EUC_H_0, g_FXCMAP_CNS_EUC_H_0_DWord, 157, 238, - FXCMAP_CMap::Range, 0}, - {"CNS-EUC-V", g_FXCMAP_CNS_EUC_V_0, g_FXCMAP_CNS_EUC_V_0_DWord, 180, 261, - FXCMAP_CMap::Range, 0}, - {"UniCNS-UCS2-H", g_FXCMAP_UniCNS_UCS2_H_3, nullptr, 16418, 0, - FXCMAP_CMap::Range, 0}, - {"UniCNS-UCS2-V", g_FXCMAP_UniCNS_UCS2_V_3, nullptr, 13, 0, - FXCMAP_CMap::Range, -1}, - {"UniCNS-UTF16-H", g_FXCMAP_UniCNS_UTF16_H_0, nullptr, 14557, 0, - FXCMAP_CMap::Single, 0}, - {"UniCNS-UTF16-V", g_FXCMAP_UniCNS_UCS2_V_3, nullptr, 13, 0, - FXCMAP_CMap::Range, -1}, }; -const size_t g_FXCMAP_CNS1_cmaps_size = FX_ArraySize(g_FXCMAP_CNS1_cmaps); +const size_t kCNS1_cmaps_size = std::size(kCNS1_cmaps); + +} // namespace fxcmap
diff --git a/core/fpdfapi/cmaps/CNS1/cmaps_cns1.h b/core/fpdfapi/cmaps/CNS1/cmaps_cns1.h index 64f6b8b..75b31cb 100644 --- a/core/fpdfapi/cmaps/CNS1/cmaps_cns1.h +++ b/core/fpdfapi/cmaps/CNS1/cmaps_cns1.h
@@ -1,4 +1,4 @@ -// Copyright 2015 PDFium Authors. All rights reserved. +// Copyright 2015 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -7,25 +7,32 @@ #ifndef CORE_FPDFAPI_CMAPS_CNS1_CMAPS_CNS1_H_ #define CORE_FPDFAPI_CMAPS_CNS1_CMAPS_CNS1_H_ +#include <stddef.h> +#include <stdint.h> + #include "core/fpdfapi/cmaps/fpdf_cmaps.h" -extern const uint16_t g_FXCMAP_B5pc_H_0[]; -extern const uint16_t g_FXCMAP_B5pc_V_0[]; -extern const uint16_t g_FXCMAP_HKscs_B5_H_5[]; -extern const uint16_t g_FXCMAP_HKscs_B5_V_5[]; -extern const uint16_t g_FXCMAP_ETen_B5_H_0[]; -extern const uint16_t g_FXCMAP_ETen_B5_V_0[]; -extern const uint16_t g_FXCMAP_ETenms_B5_H_0[]; -extern const uint16_t g_FXCMAP_ETenms_B5_V_0[]; -extern const uint16_t g_FXCMAP_CNS_EUC_H_0[]; -extern const FXCMAP_DWordCIDMap g_FXCMAP_CNS_EUC_H_0_DWord[]; -extern const uint16_t g_FXCMAP_CNS_EUC_V_0[]; -extern const FXCMAP_DWordCIDMap g_FXCMAP_CNS_EUC_V_0_DWord[]; -extern const uint16_t g_FXCMAP_UniCNS_UCS2_H_3[]; -extern const uint16_t g_FXCMAP_UniCNS_UCS2_V_3[]; -extern const uint16_t g_FXCMAP_UniCNS_UTF16_H_0[]; -extern const uint16_t g_FXCMAP_CNS1CID2Unicode_5[19088]; -extern const FXCMAP_CMap g_FXCMAP_CNS1_cmaps[]; -extern const size_t g_FXCMAP_CNS1_cmaps_size; +namespace fxcmap { + +extern const uint16_t kB5pc_H_0[]; +extern const uint16_t kB5pc_V_0[]; +extern const uint16_t kHKscs_B5_H_5[]; +extern const uint16_t kHKscs_B5_V_5[]; +extern const uint16_t kETen_B5_H_0[]; +extern const uint16_t kETen_B5_V_0[]; +extern const uint16_t kETenms_B5_H_0[]; +extern const uint16_t kETenms_B5_V_0[]; +extern const uint16_t kCNS_EUC_H_0[]; +extern const DWordCIDMap kCNS_EUC_H_0_DWord[]; +extern const uint16_t kCNS_EUC_V_0[]; +extern const DWordCIDMap kCNS_EUC_V_0_DWord[]; +extern const uint16_t kUniCNS_UCS2_H_3[]; +extern const uint16_t kUniCNS_UCS2_V_3[]; +extern const uint16_t kUniCNS_UTF16_H_0[]; +extern const uint16_t kCNS1CID2Unicode_5[19088]; +extern const CMap kCNS1_cmaps[]; +extern const size_t kCNS1_cmaps_size; + +} // namespace fxcmap #endif // CORE_FPDFAPI_CMAPS_CNS1_CMAPS_CNS1_H_
diff --git a/core/fpdfapi/cmaps/GB1/Adobe-GB1-UCS2_5.cpp b/core/fpdfapi/cmaps/GB1/Adobe-GB1-UCS2_5.cpp index 5a5ae04..b987a24 100644 --- a/core/fpdfapi/cmaps/GB1/Adobe-GB1-UCS2_5.cpp +++ b/core/fpdfapi/cmaps/GB1/Adobe-GB1-UCS2_5.cpp
@@ -1,4 +1,4 @@ -// Copyright 2014 PDFium Authors. All rights reserved. +// Copyright 2014 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -6,7 +6,9 @@ #include "core/fpdfapi/cmaps/GB1/cmaps_gb1.h" -const uint16_t g_FXCMAP_GB1CID2Unicode_5[30284] = { +namespace fxcmap { + +const uint16_t kGB1CID2Unicode_5[30284] = { 0xFFFD, 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, 0x0028, 0x0029, 0x002A, 0x002B, 0x002C, 0x002D, 0x002E, 0x002F, 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, 0x0038, 0x0039, @@ -3373,3 +3375,5 @@ 0xA4B6, 0xA4B7, 0xA4B8, 0xA4B9, 0xA4BA, 0xA4BB, 0xA4BC, 0xA4BD, 0xA4BE, 0xA4BF, 0xA4C0, 0xA4C1, 0xA4C2, 0xA4C3, 0xA4C4, 0xA4C5, 0xA4C6, }; + +} // namespace fxcmap
diff --git a/core/fpdfapi/cmaps/GB1/GB-EUC-H_0.cpp b/core/fpdfapi/cmaps/GB1/GB-EUC-H_0.cpp index 9bbfe32..6abfa33 100644 --- a/core/fpdfapi/cmaps/GB1/GB-EUC-H_0.cpp +++ b/core/fpdfapi/cmaps/GB1/GB-EUC-H_0.cpp
@@ -1,4 +1,4 @@ -// Copyright 2014 PDFium Authors. All rights reserved. +// Copyright 2014 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -6,7 +6,9 @@ #include "core/fpdfapi/cmaps/GB1/cmaps_gb1.h" -const uint16_t g_FXCMAP_GB_EUC_H_0[90 * 3] = { +namespace fxcmap { + +const uint16_t kGB_EUC_H_0[90 * 3] = { 0x0020, 0x0020, 0x1E24, 0x0021, 0x007E, 0x032E, 0xA1A1, 0xA1FE, 0x0060, 0xA2B1, 0xA2E2, 0x00BE, 0xA2E5, 0xA2EE, 0x00F0, 0xA2F1, 0xA2FC, 0x00FA, 0xA3A1, 0xA3FE, 0x0106, 0xA4A1, 0xA4F3, 0x0164, 0xA5A1, 0xA5F6, 0x01B7, @@ -38,3 +40,5 @@ 0xF2A1, 0xF2FE, 0x1BE3, 0xF3A1, 0xF3FE, 0x1C41, 0xF4A1, 0xF4FE, 0x1C9F, 0xF5A1, 0xF5FE, 0x1CFD, 0xF6A1, 0xF6FE, 0x1D5B, 0xF7A1, 0xF7FE, 0x1DB9, }; + +} // namespace fxcmap
diff --git a/core/fpdfapi/cmaps/GB1/GB-EUC-V_0.cpp b/core/fpdfapi/cmaps/GB1/GB-EUC-V_0.cpp index 19bd418..0f3d136 100644 --- a/core/fpdfapi/cmaps/GB1/GB-EUC-V_0.cpp +++ b/core/fpdfapi/cmaps/GB1/GB-EUC-V_0.cpp
@@ -1,4 +1,4 @@ -// Copyright 2014 PDFium Authors. All rights reserved. +// Copyright 2014 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -6,7 +6,9 @@ #include "core/fpdfapi/cmaps/GB1/cmaps_gb1.h" -const uint16_t g_FXCMAP_GB_EUC_V_0[20 * 3] = { +namespace fxcmap { + +const uint16_t kGB_EUC_V_0[20 * 3] = { 0xA1A2, 0xA1A2, 0x023F, 0xA1A3, 0xA1A3, 0x023E, 0xA1AA, 0xA1AA, 0x0256, 0xA1AB, 0xA1AC, 0x1E18, 0xA1AD, 0xA1AD, 0x0257, 0xA1B2, 0xA1BF, 0x0246, 0xA1FE, 0xA1FE, 0x1E1A, 0xA3A1, 0xA3A1, 0x0242, 0xA3A8, 0xA3A9, 0x0244, @@ -15,3 +17,5 @@ 0xA3DD, 0xA3DD, 0x1E1E, 0xA3DF, 0xA3DF, 0x0258, 0xA3FB, 0xA3FB, 0x0254, 0xA3FD, 0xA3FD, 0x0255, 0xA3FE, 0xA3FE, 0x1E1F, }; + +} // namespace fxcmap
diff --git a/core/fpdfapi/cmaps/GB1/GBK-EUC-H_2.cpp b/core/fpdfapi/cmaps/GB1/GBK-EUC-H_2.cpp index 617f020..5cfc25f 100644 --- a/core/fpdfapi/cmaps/GB1/GBK-EUC-H_2.cpp +++ b/core/fpdfapi/cmaps/GB1/GBK-EUC-H_2.cpp
@@ -1,4 +1,4 @@ -// Copyright 2014 PDFium Authors. All rights reserved. +// Copyright 2014 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -6,7 +6,9 @@ #include "core/fpdfapi/cmaps/GB1/cmaps_gb1.h" -const uint16_t g_FXCMAP_GBK_EUC_H_2[4071 * 3] = { +namespace fxcmap { + +const uint16_t kGBK_EUC_H_2[4071 * 3] = { 0x0020, 0x0020, 0x1E24, 0x0021, 0x007E, 0x032E, 0x8140, 0x8178, 0x2758, 0x8179, 0x8179, 0x2059, 0x817A, 0x817E, 0x2791, 0x8180, 0x8185, 0x2796, 0x8186, 0x8186, 0x21F1, 0x8187, 0x81EC, 0x279C, 0x81ED, 0x81ED, 0x1FF2, @@ -1365,3 +1367,5 @@ 0xFD9E, 0xFD9E, 0x40D3, 0xFD9F, 0xFD9F, 0x200C, 0xFDA0, 0xFDA0, 0x5083, 0xFE40, 0xFE40, 0x1259, 0xFE41, 0xFE7E, 0x5610, 0xFE80, 0xFEA0, 0x564E, }; + +} // namespace fxcmap
diff --git a/core/fpdfapi/cmaps/GB1/GBK-EUC-V_2.cpp b/core/fpdfapi/cmaps/GB1/GBK-EUC-V_2.cpp index 87e53a7..ea59b41 100644 --- a/core/fpdfapi/cmaps/GB1/GBK-EUC-V_2.cpp +++ b/core/fpdfapi/cmaps/GB1/GBK-EUC-V_2.cpp
@@ -1,4 +1,4 @@ -// Copyright 2014 PDFium Authors. All rights reserved. +// Copyright 2014 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -6,7 +6,9 @@ #include "core/fpdfapi/cmaps/GB1/cmaps_gb1.h" -const uint16_t g_FXCMAP_GBK_EUC_V_2[20 * 3] = { +namespace fxcmap { + +const uint16_t kGBK_EUC_V_2[20 * 3] = { 0xA1A2, 0xA1A2, 0x023F, 0xA1A3, 0xA1A3, 0x023E, 0xA1AA, 0xA1AA, 0x0256, 0xA1AB, 0xA1AC, 0x1E18, 0xA1AD, 0xA1AD, 0x0257, 0xA1B2, 0xA1BF, 0x0246, 0xA1FE, 0xA1FE, 0x1E1A, 0xA3A1, 0xA3A1, 0x0242, 0xA3A8, 0xA3A9, 0x0244, @@ -15,3 +17,5 @@ 0xA3DD, 0xA3DD, 0x1E1E, 0xA3DF, 0xA3DF, 0x0258, 0xA3FB, 0xA3FB, 0x0254, 0xA3FD, 0xA3FD, 0x0255, 0xA3FE, 0xA3FE, 0x1E1F, }; + +} // namespace fxcmap
diff --git a/core/fpdfapi/cmaps/GB1/GBK2K-H_5.cpp b/core/fpdfapi/cmaps/GB1/GBK2K-H_5.cpp index 7d7b48a..4ac5804 100644 --- a/core/fpdfapi/cmaps/GB1/GBK2K-H_5.cpp +++ b/core/fpdfapi/cmaps/GB1/GBK2K-H_5.cpp
@@ -1,4 +1,4 @@ -// Copyright 2014 PDFium Authors. All rights reserved. +// Copyright 2014 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -6,7 +6,9 @@ #include "core/fpdfapi/cmaps/GB1/cmaps_gb1.h" -const uint16_t g_FXCMAP_GBK2K_H_5[4071 * 3] = { +namespace fxcmap { + +const uint16_t kGBK2K_H_5[4071 * 3] = { 0x0020, 0x007E, 0x0001, 0x8140, 0x8178, 0x2758, 0x8179, 0x8179, 0x2059, 0x817A, 0x817E, 0x2791, 0x8180, 0x8185, 0x2796, 0x8186, 0x8186, 0x21F1, 0x8187, 0x81EC, 0x279C, 0x81ED, 0x81ED, 0x1FF2, 0x81EE, 0x81F5, 0x2802, @@ -1366,7 +1368,7 @@ 0xFE40, 0xFE40, 0x1259, 0xFE41, 0xFE7E, 0x5610, 0xFE80, 0xFEA0, 0x564E, }; -const FXCMAP_DWordCIDMap g_FXCMAP_GBK2K_H_5_DWord[1017] = { +const DWordCIDMap kGBK2K_H_5_DWord[1017] = { {0x8130, 0x8436, 0x8436, 0x5752}, {0x8138, 0xFD38, 0xFD39, 0x579C}, {0x8138, 0xFE30, 0xFE39, 0x579E}, {0x8139, 0x8130, 0x8137, 0x57A8}, {0x8139, 0x8139, 0x8139, 0x57B0}, {0x8139, 0x8230, 0x8239, 0x57B1}, @@ -1877,3 +1879,5 @@ {0x8236, 0x9230, 0x9239, 0x7632}, {0x8236, 0x9330, 0x9339, 0x763C}, {0x8236, 0x9430, 0x9435, 0x7646}, }; + +} // namespace fxcmap
diff --git a/core/fpdfapi/cmaps/GB1/GBK2K-V_5.cpp b/core/fpdfapi/cmaps/GB1/GBK2K-V_5.cpp index 8efedd0..904253f 100644 --- a/core/fpdfapi/cmaps/GB1/GBK2K-V_5.cpp +++ b/core/fpdfapi/cmaps/GB1/GBK2K-V_5.cpp
@@ -1,4 +1,4 @@ -// Copyright 2014 PDFium Authors. All rights reserved. +// Copyright 2014 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -6,7 +6,9 @@ #include "core/fpdfapi/cmaps/GB1/cmaps_gb1.h" -const uint16_t g_FXCMAP_GBK2K_V_5[41 * 3] = { +namespace fxcmap { + +const uint16_t kGBK2K_V_5[41 * 3] = { 0xA1A2, 0xA1A2, 0x023F, 0xA1A3, 0xA1A3, 0x023E, 0xA1AA, 0xA1AA, 0x0256, 0xA1AB, 0xA1AC, 0x1E18, 0xA1AD, 0xA1AD, 0x0257, 0xA1B2, 0xA1BF, 0x0246, 0xA1FE, 0xA1FE, 0x1E1A, 0xA3A1, 0xA3A1, 0x0242, 0xA3A8, 0xA3A9, 0x0244, @@ -22,3 +24,5 @@ 0xA5E3, 0xA5E3, 0x5773, 0xA5E5, 0xA5E5, 0x5775, 0xA5E7, 0xA5E7, 0x5774, 0xA5EE, 0xA5EE, 0x5772, 0xA960, 0xA960, 0x577A, }; + +} // namespace fxcmap
diff --git a/core/fpdfapi/cmaps/GB1/GBKp-EUC-H_2.cpp b/core/fpdfapi/cmaps/GB1/GBKp-EUC-H_2.cpp index 3145980..2de5aea 100644 --- a/core/fpdfapi/cmaps/GB1/GBKp-EUC-H_2.cpp +++ b/core/fpdfapi/cmaps/GB1/GBKp-EUC-H_2.cpp
@@ -1,4 +1,4 @@ -// Copyright 2014 PDFium Authors. All rights reserved. +// Copyright 2014 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -6,7 +6,9 @@ #include "core/fpdfapi/cmaps/GB1/cmaps_gb1.h" -const uint16_t g_FXCMAP_GBKp_EUC_H_2[4070 * 3] = { +namespace fxcmap { + +const uint16_t kGBKp_EUC_H_2[4070 * 3] = { 0x0020, 0x007E, 0x0001, 0x8140, 0x8178, 0x2758, 0x8179, 0x8179, 0x2059, 0x817A, 0x817E, 0x2791, 0x8180, 0x8185, 0x2796, 0x8186, 0x8186, 0x21F1, 0x8187, 0x81EC, 0x279C, 0x81ED, 0x81ED, 0x1FF2, 0x81EE, 0x81F5, 0x2802, @@ -1365,3 +1367,5 @@ 0xFD9F, 0xFD9F, 0x200C, 0xFDA0, 0xFDA0, 0x5083, 0xFE40, 0xFE40, 0x1259, 0xFE41, 0xFE7E, 0x5610, 0xFE80, 0xFEA0, 0x564E, }; + +} // namespace fxcmap
diff --git a/core/fpdfapi/cmaps/GB1/GBKp-EUC-V_2.cpp b/core/fpdfapi/cmaps/GB1/GBKp-EUC-V_2.cpp index 014ae70..aa55cf8 100644 --- a/core/fpdfapi/cmaps/GB1/GBKp-EUC-V_2.cpp +++ b/core/fpdfapi/cmaps/GB1/GBKp-EUC-V_2.cpp
@@ -1,4 +1,4 @@ -// Copyright 2014 PDFium Authors. All rights reserved. +// Copyright 2014 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -6,7 +6,9 @@ #include "core/fpdfapi/cmaps/GB1/cmaps_gb1.h" -const uint16_t g_FXCMAP_GBKp_EUC_V_2[20 * 3] = { +namespace fxcmap { + +const uint16_t kGBKp_EUC_V_2[20 * 3] = { 0xA1A2, 0xA1A2, 0x023F, 0xA1A3, 0xA1A3, 0x023E, 0xA1AA, 0xA1AA, 0x0256, 0xA1AB, 0xA1AC, 0x1E18, 0xA1AD, 0xA1AD, 0x0257, 0xA1B2, 0xA1BF, 0x0246, 0xA1FE, 0xA1FE, 0x1E1A, 0xA3A1, 0xA3A1, 0x0242, 0xA3A8, 0xA3A9, 0x0244, @@ -15,3 +17,5 @@ 0xA3DD, 0xA3DD, 0x1E1E, 0xA3DF, 0xA3DF, 0x0258, 0xA3FB, 0xA3FB, 0x0254, 0xA3FD, 0xA3FD, 0x0255, 0xA3FE, 0xA3FE, 0x1E1F, }; + +} // namespace fxcmap
diff --git a/core/fpdfapi/cmaps/GB1/GBpc-EUC-H_0.cpp b/core/fpdfapi/cmaps/GB1/GBpc-EUC-H_0.cpp index ff437d7..f1f6dd3 100644 --- a/core/fpdfapi/cmaps/GB1/GBpc-EUC-H_0.cpp +++ b/core/fpdfapi/cmaps/GB1/GBpc-EUC-H_0.cpp
@@ -1,4 +1,4 @@ -// Copyright 2014 PDFium Authors. All rights reserved. +// Copyright 2014 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -6,7 +6,9 @@ #include "core/fpdfapi/cmaps/GB1/cmaps_gb1.h" -const uint16_t g_FXCMAP_GBpc_EUC_H_0[91 * 3] = { +namespace fxcmap { + +const uint16_t kGBpc_EUC_H_0[91 * 3] = { 0x0020, 0x007E, 0x0001, 0x0080, 0x0080, 0x1E20, 0x00FD, 0x00FF, 0x1E21, 0xA1A1, 0xA1FE, 0x0060, 0xA2B1, 0xA2E2, 0x00BE, 0xA2E5, 0xA2EE, 0x00F0, 0xA2F1, 0xA2FC, 0x00FA, 0xA3A1, 0xA3FE, 0x0106, 0xA4A1, 0xA4F3, 0x0164, @@ -39,3 +41,5 @@ 0xF4A1, 0xF4FE, 0x1C9F, 0xF5A1, 0xF5FE, 0x1CFD, 0xF6A1, 0xF6FE, 0x1D5B, 0xF7A1, 0xF7FE, 0x1DB9, }; + +} // namespace fxcmap
diff --git a/core/fpdfapi/cmaps/GB1/GBpc-EUC-V_0.cpp b/core/fpdfapi/cmaps/GB1/GBpc-EUC-V_0.cpp index a35858f..3b53117 100644 --- a/core/fpdfapi/cmaps/GB1/GBpc-EUC-V_0.cpp +++ b/core/fpdfapi/cmaps/GB1/GBpc-EUC-V_0.cpp
@@ -1,4 +1,4 @@ -// Copyright 2014 PDFium Authors. All rights reserved. +// Copyright 2014 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -6,7 +6,9 @@ #include "core/fpdfapi/cmaps/GB1/cmaps_gb1.h" -const uint16_t g_FXCMAP_GBpc_EUC_V_0[20 * 3] = { +namespace fxcmap { + +const uint16_t kGBpc_EUC_V_0[20 * 3] = { 0xA1A2, 0xA1A2, 0x023F, 0xA1A3, 0xA1A3, 0x023E, 0xA1AA, 0xA1AA, 0x0256, 0xA1AB, 0xA1AC, 0x1E18, 0xA1AD, 0xA1AD, 0x0257, 0xA1B2, 0xA1BF, 0x0246, 0xA1FE, 0xA1FE, 0x1E1A, 0xA3A1, 0xA3A1, 0x0242, 0xA3A8, 0xA3A9, 0x0244, @@ -15,3 +17,5 @@ 0xA3DD, 0xA3DD, 0x1E1E, 0xA3DF, 0xA3DF, 0x0258, 0xA3FB, 0xA3FB, 0x0254, 0xA3FD, 0xA3FD, 0x0255, 0xA3FE, 0xA3FE, 0x1E1F, }; + +} // namespace fxcmap
diff --git a/core/fpdfapi/cmaps/GB1/UniGB-UCS2-H_4.cpp b/core/fpdfapi/cmaps/GB1/UniGB-UCS2-H_4.cpp index e135f40..a787a34 100644 --- a/core/fpdfapi/cmaps/GB1/UniGB-UCS2-H_4.cpp +++ b/core/fpdfapi/cmaps/GB1/UniGB-UCS2-H_4.cpp
@@ -1,4 +1,4 @@ -// Copyright 2014 PDFium Authors. All rights reserved. +// Copyright 2014 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -6,7 +6,9 @@ #include "core/fpdfapi/cmaps/GB1/cmaps_gb1.h" -const uint16_t g_FXCMAP_UniGB_UCS2_H_4[13825 * 3] = { +namespace fxcmap { + +const uint16_t kUniGB_UCS2_H_4[13825 * 3] = { 0x0020, 0x007E, 0x0001, 0x00A4, 0x00A4, 0x00A7, 0x00A5, 0x00A5, 0x5752, 0x00A7, 0x00A7, 0x00AB, 0x00A8, 0x00A8, 0x0066, 0x00B0, 0x00B0, 0x00A2, 0x00B1, 0x00B1, 0x007F, 0x00D7, 0x00D7, 0x0080, 0x00E0, 0x00E0, 0x029F, @@ -4617,3 +4619,5 @@ 0xFFE2, 0xFFE2, 0x271E, 0xFFE3, 0xFFE3, 0x0163, 0xFFE4, 0xFFE4, 0x271F, 0xFFE5, 0xFFE5, 0x0109, }; + +} // namespace fxcmap
diff --git a/core/fpdfapi/cmaps/GB1/UniGB-UCS2-V_4.cpp b/core/fpdfapi/cmaps/GB1/UniGB-UCS2-V_4.cpp index 4ec5405..34ab6e7 100644 --- a/core/fpdfapi/cmaps/GB1/UniGB-UCS2-V_4.cpp +++ b/core/fpdfapi/cmaps/GB1/UniGB-UCS2-V_4.cpp
@@ -1,4 +1,4 @@ -// Copyright 2014 PDFium Authors. All rights reserved. +// Copyright 2014 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -6,7 +6,9 @@ #include "core/fpdfapi/cmaps/GB1/cmaps_gb1.h" -const uint16_t g_FXCMAP_UniGB_UCS2_V_4[24 * 3] = { +namespace fxcmap { + +const uint16_t kUniGB_UCS2_V_4[24 * 3] = { 0x2014, 0x2014, 0x0256, 0x2026, 0x2026, 0x0257, 0x2225, 0x2225, 0x1E1C, 0x3001, 0x3001, 0x023F, 0x3002, 0x3002, 0x023E, 0x3008, 0x300F, 0x0248, 0x3010, 0x3011, 0x0252, 0x3013, 0x3013, 0x1E1A, 0x3014, 0x3015, 0x0246, @@ -16,3 +18,5 @@ 0xFF3D, 0xFF3D, 0x1E1E, 0xFF3F, 0xFF3F, 0x0258, 0xFF5B, 0xFF5B, 0x0254, 0xFF5D, 0xFF5D, 0x0255, 0xFF5E, 0xFF5E, 0x1E18, 0xFFE3, 0xFFE3, 0x1E1F, }; + +} // namespace fxcmap
diff --git a/core/fpdfapi/cmaps/GB1/cmaps_gb1.cpp b/core/fpdfapi/cmaps/GB1/cmaps_gb1.cpp index a598091..facf123 100644 --- a/core/fpdfapi/cmaps/GB1/cmaps_gb1.cpp +++ b/core/fpdfapi/cmaps/GB1/cmaps_gb1.cpp
@@ -1,4 +1,4 @@ -// Copyright 2014 PDFium Authors. All rights reserved. +// Copyright 2014 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -6,33 +6,29 @@ #include "core/fpdfapi/cmaps/GB1/cmaps_gb1.h" -#include "core/fxcrt/fx_memory.h" +#include <iterator> -const FXCMAP_CMap g_FXCMAP_GB1_cmaps[] = { - {"GB-EUC-H", g_FXCMAP_GB_EUC_H_0, nullptr, 90, 0, FXCMAP_CMap::Range, 0}, - {"GB-EUC-V", g_FXCMAP_GB_EUC_V_0, nullptr, 20, 0, FXCMAP_CMap::Range, -1}, - {"GBpc-EUC-H", g_FXCMAP_GBpc_EUC_H_0, nullptr, 91, 0, FXCMAP_CMap::Range, +namespace fxcmap { + +const CMap kGB1_cmaps[] = { + {"GB-EUC-H", kGB_EUC_H_0, nullptr, 90, 0, CMap::Type::kRange, 0}, + {"GB-EUC-V", kGB_EUC_V_0, nullptr, 20, 0, CMap::Type::kRange, -1}, + {"GBpc-EUC-H", kGBpc_EUC_H_0, nullptr, 91, 0, CMap::Type::kRange, 0}, + {"GBpc-EUC-V", kGBpc_EUC_V_0, nullptr, 20, 0, CMap::Type::kRange, -1}, + {"GBK-EUC-H", kGBK_EUC_H_2, nullptr, 4071, 0, CMap::Type::kRange, 0}, + {"GBK-EUC-V", kGBK_EUC_V_2, nullptr, 20, 0, CMap::Type::kRange, -1}, + {"GBKp-EUC-H", kGBKp_EUC_H_2, nullptr, 4070, 0, CMap::Type::kRange, -2}, + {"GBKp-EUC-V", kGBKp_EUC_V_2, nullptr, 20, 0, CMap::Type::kRange, -1}, + {"GBK2K-H", kGBK2K_H_5, kGBK2K_H_5_DWord, 4071, 1017, CMap::Type::kRange, + -4}, + {"GBK2K-V", kGBK2K_V_5, nullptr, 41, 0, CMap::Type::kRange, -1}, + {"UniGB-UCS2-H", kUniGB_UCS2_H_4, nullptr, 13825, 0, CMap::Type::kRange, 0}, + {"UniGB-UCS2-V", kUniGB_UCS2_V_4, nullptr, 24, 0, CMap::Type::kRange, -1}, + {"UniGB-UTF16-H", kUniGB_UCS2_H_4, nullptr, 13825, 0, CMap::Type::kRange, 0}, - {"GBpc-EUC-V", g_FXCMAP_GBpc_EUC_V_0, nullptr, 20, 0, FXCMAP_CMap::Range, - -1}, - {"GBK-EUC-H", g_FXCMAP_GBK_EUC_H_2, nullptr, 4071, 0, FXCMAP_CMap::Range, - 0}, - {"GBK-EUC-V", g_FXCMAP_GBK_EUC_V_2, nullptr, 20, 0, FXCMAP_CMap::Range, -1}, - {"GBKp-EUC-H", g_FXCMAP_GBKp_EUC_H_2, nullptr, 4070, 0, FXCMAP_CMap::Range, - -2}, - {"GBKp-EUC-V", g_FXCMAP_GBKp_EUC_V_2, nullptr, 20, 0, FXCMAP_CMap::Range, - -1}, - {"GBK2K-H", g_FXCMAP_GBK2K_H_5, g_FXCMAP_GBK2K_H_5_DWord, 4071, 1017, - FXCMAP_CMap::Range, -4}, - {"GBK2K-V", g_FXCMAP_GBK2K_V_5, nullptr, 41, 0, FXCMAP_CMap::Range, -1}, - {"UniGB-UCS2-H", g_FXCMAP_UniGB_UCS2_H_4, nullptr, 13825, 0, - FXCMAP_CMap::Range, 0}, - {"UniGB-UCS2-V", g_FXCMAP_UniGB_UCS2_V_4, nullptr, 24, 0, - FXCMAP_CMap::Range, -1}, - {"UniGB-UTF16-H", g_FXCMAP_UniGB_UCS2_H_4, nullptr, 13825, 0, - FXCMAP_CMap::Range, 0}, - {"UniGB-UTF16-V", g_FXCMAP_UniGB_UCS2_V_4, nullptr, 24, 0, - FXCMAP_CMap::Range, -1}, + {"UniGB-UTF16-V", kUniGB_UCS2_V_4, nullptr, 24, 0, CMap::Type::kRange, -1}, }; -const size_t g_FXCMAP_GB1_cmaps_size = FX_ArraySize(g_FXCMAP_GB1_cmaps); +const size_t kGB1_cmaps_size = std::size(kGB1_cmaps); + +} // namespace fxcmap
diff --git a/core/fpdfapi/cmaps/GB1/cmaps_gb1.h b/core/fpdfapi/cmaps/GB1/cmaps_gb1.h index 7873f64..a226266 100644 --- a/core/fpdfapi/cmaps/GB1/cmaps_gb1.h +++ b/core/fpdfapi/cmaps/GB1/cmaps_gb1.h
@@ -1,4 +1,4 @@ -// Copyright 2015 PDFium Authors. All rights reserved. +// Copyright 2015 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -7,23 +7,30 @@ #ifndef CORE_FPDFAPI_CMAPS_GB1_CMAPS_GB1_H_ #define CORE_FPDFAPI_CMAPS_GB1_CMAPS_GB1_H_ +#include <stddef.h> +#include <stdint.h> + #include "core/fpdfapi/cmaps/fpdf_cmaps.h" -extern const uint16_t g_FXCMAP_GB_EUC_H_0[]; -extern const uint16_t g_FXCMAP_GB_EUC_V_0[]; -extern const uint16_t g_FXCMAP_GBpc_EUC_H_0[]; -extern const uint16_t g_FXCMAP_GBpc_EUC_V_0[]; -extern const uint16_t g_FXCMAP_GBK_EUC_H_2[]; -extern const uint16_t g_FXCMAP_GBK_EUC_V_2[]; -extern const uint16_t g_FXCMAP_GBKp_EUC_H_2[]; -extern const uint16_t g_FXCMAP_GBKp_EUC_V_2[]; -extern const uint16_t g_FXCMAP_GBK2K_H_5[]; -extern const FXCMAP_DWordCIDMap g_FXCMAP_GBK2K_H_5_DWord[]; -extern const uint16_t g_FXCMAP_GBK2K_V_5[]; -extern const uint16_t g_FXCMAP_UniGB_UCS2_H_4[]; -extern const uint16_t g_FXCMAP_UniGB_UCS2_V_4[]; -extern const uint16_t g_FXCMAP_GB1CID2Unicode_5[30284]; -extern const FXCMAP_CMap g_FXCMAP_GB1_cmaps[]; -extern const size_t g_FXCMAP_GB1_cmaps_size; +namespace fxcmap { + +extern const uint16_t kGB_EUC_H_0[]; +extern const uint16_t kGB_EUC_V_0[]; +extern const uint16_t kGBpc_EUC_H_0[]; +extern const uint16_t kGBpc_EUC_V_0[]; +extern const uint16_t kGBK_EUC_H_2[]; +extern const uint16_t kGBK_EUC_V_2[]; +extern const uint16_t kGBKp_EUC_H_2[]; +extern const uint16_t kGBKp_EUC_V_2[]; +extern const uint16_t kGBK2K_H_5[]; +extern const DWordCIDMap kGBK2K_H_5_DWord[]; +extern const uint16_t kGBK2K_V_5[]; +extern const uint16_t kUniGB_UCS2_H_4[]; +extern const uint16_t kUniGB_UCS2_V_4[]; +extern const uint16_t kGB1CID2Unicode_5[30284]; +extern const CMap kGB1_cmaps[]; +extern const size_t kGB1_cmaps_size; + +} // namespace fxcmap #endif // CORE_FPDFAPI_CMAPS_GB1_CMAPS_GB1_H_
diff --git a/core/fpdfapi/cmaps/Japan1/83pv-RKSJ-H_1.cpp b/core/fpdfapi/cmaps/Japan1/83pv-RKSJ-H_1.cpp index b3447af..51b49e2 100644 --- a/core/fpdfapi/cmaps/Japan1/83pv-RKSJ-H_1.cpp +++ b/core/fpdfapi/cmaps/Japan1/83pv-RKSJ-H_1.cpp
@@ -1,4 +1,4 @@ -// Copyright 2014 PDFium Authors. All rights reserved. +// Copyright 2014 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -6,7 +6,9 @@ #include "core/fpdfapi/cmaps/Japan1/cmaps_japan1.h" -const uint16_t g_FXCMAP_83pv_RKSJ_H_1[222 * 3] = { +namespace fxcmap { + +const uint16_t k83pv_RKSJ_H_1[222 * 3] = { 0x0020, 0x007E, 0x0001, 0x0080, 0x0080, 0x0061, 0x00A0, 0x00DF, 0x0146, 0x00FD, 0x00FD, 0x0098, 0x00FE, 0x00FE, 0x00E4, 0x00FF, 0x00FF, 0x007C, 0x8140, 0x817E, 0x0279, 0x8180, 0x81AC, 0x02B8, 0x81B8, 0x81BF, 0x02E5, @@ -82,3 +84,5 @@ 0xEE90, 0xEE90, 0x02FA, 0xEE91, 0xEE91, 0x02F9, 0xEE92, 0xEE92, 0x0301, 0xEE93, 0xEE99, 0x1DC8, 0xEE9A, 0xEE9A, 0x0300, 0xEE9B, 0xEE9C, 0x1DCF, }; + +} // namespace fxcmap
diff --git a/core/fpdfapi/cmaps/Japan1/90ms-RKSJ-H_2.cpp b/core/fpdfapi/cmaps/Japan1/90ms-RKSJ-H_2.cpp index d5d29d6..212f809 100644 --- a/core/fpdfapi/cmaps/Japan1/90ms-RKSJ-H_2.cpp +++ b/core/fpdfapi/cmaps/Japan1/90ms-RKSJ-H_2.cpp
@@ -1,4 +1,4 @@ -// Copyright 2014 PDFium Authors. All rights reserved. +// Copyright 2014 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -6,7 +6,9 @@ #include "core/fpdfapi/cmaps/Japan1/cmaps_japan1.h" -const uint16_t g_FXCMAP_90ms_RKSJ_H_2[171 * 3] = { +namespace fxcmap { + +const uint16_t k90ms_RKSJ_H_2[171 * 3] = { 0x0020, 0x007D, 0x00E7, 0x007E, 0x007E, 0x0277, 0x00A0, 0x00DF, 0x0146, 0x8140, 0x817E, 0x0279, 0x8180, 0x81AC, 0x02B8, 0x81B8, 0x81BF, 0x02E5, 0x81C8, 0x81CE, 0x02ED, 0x81DA, 0x81E8, 0x02F4, 0x81F0, 0x81F7, 0x0303, @@ -65,3 +67,5 @@ 0xFA80, 0xFACF, 0x20CA, 0xFAD0, 0xFAD0, 0x07C9, 0xFAD1, 0xFAFC, 0x211A, 0xFB40, 0xFB7E, 0x2146, 0xFB80, 0xFBFC, 0x2185, 0xFC40, 0xFC4B, 0x2202, }; + +} // namespace fxcmap
diff --git a/core/fpdfapi/cmaps/Japan1/90ms-RKSJ-V_2.cpp b/core/fpdfapi/cmaps/Japan1/90ms-RKSJ-V_2.cpp index 1fb0c33..5303c72 100644 --- a/core/fpdfapi/cmaps/Japan1/90ms-RKSJ-V_2.cpp +++ b/core/fpdfapi/cmaps/Japan1/90ms-RKSJ-V_2.cpp
@@ -1,4 +1,4 @@ -// Copyright 2014 PDFium Authors. All rights reserved. +// Copyright 2014 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -6,7 +6,9 @@ #include "core/fpdfapi/cmaps/Japan1/cmaps_japan1.h" -const uint16_t g_FXCMAP_90ms_RKSJ_V_2[78 * 3] = { +namespace fxcmap { + +const uint16_t k90ms_RKSJ_V_2[78 * 3] = { 0x8141, 0x8142, 0x1ECF, 0x8143, 0x8143, 0x204C, 0x8144, 0x8144, 0x2052, 0x8150, 0x8151, 0x1ED1, 0x815B, 0x815D, 0x1ED3, 0x8160, 0x8164, 0x1ED6, 0x8169, 0x817A, 0x1EDB, 0x8181, 0x8181, 0x1EED, 0x81A8, 0x81A8, 0x02E3, @@ -34,3 +36,5 @@ 0x8768, 0x8768, 0x2098, 0x8769, 0x876A, 0x1F0E, 0x876B, 0x876B, 0x209C, 0x876C, 0x876D, 0x1F11, 0x876E, 0x876E, 0x209D, 0x8780, 0x8781, 0x1F14, }; + +} // namespace fxcmap
diff --git a/core/fpdfapi/cmaps/Japan1/90msp-RKSJ-H_2.cpp b/core/fpdfapi/cmaps/Japan1/90msp-RKSJ-H_2.cpp index 65081c8..a77d0e1 100644 --- a/core/fpdfapi/cmaps/Japan1/90msp-RKSJ-H_2.cpp +++ b/core/fpdfapi/cmaps/Japan1/90msp-RKSJ-H_2.cpp
@@ -1,4 +1,4 @@ -// Copyright 2014 PDFium Authors. All rights reserved. +// Copyright 2014 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -6,7 +6,9 @@ #include "core/fpdfapi/cmaps/Japan1/cmaps_japan1.h" -const uint16_t g_FXCMAP_90msp_RKSJ_H_2[170 * 3] = { +namespace fxcmap { + +const uint16_t k90msp_RKSJ_H_2[170 * 3] = { 0x0020, 0x007E, 0x0001, 0x00A0, 0x00DF, 0x0146, 0x8140, 0x817E, 0x0279, 0x8180, 0x81AC, 0x02B8, 0x81B8, 0x81BF, 0x02E5, 0x81C8, 0x81CE, 0x02ED, 0x81DA, 0x81E8, 0x02F4, 0x81F0, 0x81F7, 0x0303, 0x81FC, 0x81FC, 0x030B, @@ -65,3 +67,5 @@ 0xFAD0, 0xFAD0, 0x07C9, 0xFAD1, 0xFAFC, 0x211A, 0xFB40, 0xFB7E, 0x2146, 0xFB80, 0xFBFC, 0x2185, 0xFC40, 0xFC4B, 0x2202, }; + +} // namespace fxcmap
diff --git a/core/fpdfapi/cmaps/Japan1/90msp-RKSJ-V_2.cpp b/core/fpdfapi/cmaps/Japan1/90msp-RKSJ-V_2.cpp index 5a5e457..ee2f799 100644 --- a/core/fpdfapi/cmaps/Japan1/90msp-RKSJ-V_2.cpp +++ b/core/fpdfapi/cmaps/Japan1/90msp-RKSJ-V_2.cpp
@@ -1,4 +1,4 @@ -// Copyright 2014 PDFium Authors. All rights reserved. +// Copyright 2014 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -6,7 +6,9 @@ #include "core/fpdfapi/cmaps/Japan1/cmaps_japan1.h" -const uint16_t g_FXCMAP_90msp_RKSJ_V_2[78 * 3] = { +namespace fxcmap { + +const uint16_t k90msp_RKSJ_V_2[78 * 3] = { 0x8141, 0x8142, 0x1ECF, 0x8143, 0x8143, 0x204C, 0x8144, 0x8144, 0x2052, 0x8150, 0x8151, 0x1ED1, 0x815B, 0x815D, 0x1ED3, 0x8160, 0x8164, 0x1ED6, 0x8169, 0x817A, 0x1EDB, 0x8181, 0x8181, 0x1EED, 0x81A8, 0x81A8, 0x02E3, @@ -34,3 +36,5 @@ 0x8768, 0x8768, 0x2098, 0x8769, 0x876A, 0x1F0E, 0x876B, 0x876B, 0x209C, 0x876C, 0x876D, 0x1F11, 0x876E, 0x876E, 0x209D, 0x8780, 0x8781, 0x1F14, }; + +} // namespace fxcmap
diff --git a/core/fpdfapi/cmaps/Japan1/90pv-RKSJ-H_1.cpp b/core/fpdfapi/cmaps/Japan1/90pv-RKSJ-H_1.cpp index e41b839..0bf3f2f 100644 --- a/core/fpdfapi/cmaps/Japan1/90pv-RKSJ-H_1.cpp +++ b/core/fpdfapi/cmaps/Japan1/90pv-RKSJ-H_1.cpp
@@ -1,4 +1,4 @@ -// Copyright 2014 PDFium Authors. All rights reserved. +// Copyright 2014 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -6,7 +6,9 @@ #include "core/fpdfapi/cmaps/Japan1/cmaps_japan1.h" -const uint16_t g_FXCMAP_90pv_RKSJ_H_1[263 * 3] = { +namespace fxcmap { + +const uint16_t k90pv_RKSJ_H_1[263 * 3] = { 0x0020, 0x007E, 0x0001, 0x0080, 0x0080, 0x0061, 0x00A0, 0x00DF, 0x0146, 0x00FD, 0x00FD, 0x0098, 0x00FE, 0x00FE, 0x00E4, 0x00FF, 0x00FF, 0x007C, 0x8140, 0x817E, 0x0279, 0x8180, 0x81AC, 0x02B8, 0x81B8, 0x81BF, 0x02E5, @@ -96,3 +98,5 @@ 0xED83, 0xED83, 0x1EFE, 0xED85, 0xED85, 0x1EFF, 0xED87, 0xED87, 0x1F00, 0xED8E, 0xED8E, 0x1F01, 0xED95, 0xED96, 0x1F02, }; + +} // namespace fxcmap
diff --git a/core/fpdfapi/cmaps/Japan1/Add-RKSJ-H_1.cpp b/core/fpdfapi/cmaps/Japan1/Add-RKSJ-H_1.cpp index 53dc754..69af127 100644 --- a/core/fpdfapi/cmaps/Japan1/Add-RKSJ-H_1.cpp +++ b/core/fpdfapi/cmaps/Japan1/Add-RKSJ-H_1.cpp
@@ -1,4 +1,4 @@ -// Copyright 2014 PDFium Authors. All rights reserved. +// Copyright 2014 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -6,7 +6,9 @@ #include "core/fpdfapi/cmaps/Japan1/cmaps_japan1.h" -const uint16_t g_FXCMAP_Add_RKSJ_H_1[635 * 3] = { +namespace fxcmap { + +const uint16_t kAdd_RKSJ_H_1[635 * 3] = { 0x0020, 0x007E, 0x00E7, 0x00A0, 0x00DF, 0x0146, 0x8140, 0x817E, 0x0279, 0x8180, 0x81AC, 0x02B8, 0x81B8, 0x81BF, 0x02E5, 0x81C8, 0x81CE, 0x02ED, 0x81DA, 0x81E8, 0x02F4, 0x81F0, 0x81F7, 0x0303, 0x81FC, 0x81FC, 0x030B, @@ -220,3 +222,5 @@ 0xEF52, 0xEF63, 0x1EDB, 0xEF64, 0xEF79, 0x1EEE, 0xEF7A, 0xEF7B, 0x2048, 0xEF8D, 0xEF90, 0x02E0, 0xEF91, 0xEF94, 0x1FF6, }; + +} // namespace fxcmap
diff --git a/core/fpdfapi/cmaps/Japan1/Add-RKSJ-V_1.cpp b/core/fpdfapi/cmaps/Japan1/Add-RKSJ-V_1.cpp index 47be931..ce351ff 100644 --- a/core/fpdfapi/cmaps/Japan1/Add-RKSJ-V_1.cpp +++ b/core/fpdfapi/cmaps/Japan1/Add-RKSJ-V_1.cpp
@@ -1,4 +1,4 @@ -// Copyright 2014 PDFium Authors. All rights reserved. +// Copyright 2014 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -6,7 +6,9 @@ #include "core/fpdfapi/cmaps/Japan1/cmaps_japan1.h" -const uint16_t g_FXCMAP_Add_RKSJ_V_1[57 * 3] = { +namespace fxcmap { + +const uint16_t kAdd_RKSJ_V_1[57 * 3] = { 0x8141, 0x8142, 0x1ECF, 0x8143, 0x8143, 0x204C, 0x8144, 0x8144, 0x2052, 0x8150, 0x8151, 0x1ED1, 0x815B, 0x815D, 0x1ED3, 0x8160, 0x8164, 0x1ED6, 0x8165, 0x8165, 0x205A, 0x8166, 0x8166, 0x2053, 0x8167, 0x8167, 0x2058, @@ -27,3 +29,5 @@ 0xEC8D, 0xEC8D, 0x20A6, 0xEC8E, 0xEC8E, 0x20A5, 0xEC8F, 0xEC8F, 0x20A1, 0xEC90, 0xEC90, 0x20A4, 0xEC95, 0xEC95, 0x2084, 0xEF92, 0xEF92, 0x208D, }; + +} // namespace fxcmap
diff --git a/core/fpdfapi/cmaps/Japan1/Adobe-Japan1-UCS2_4.cpp b/core/fpdfapi/cmaps/Japan1/Adobe-Japan1-UCS2_4.cpp index fbef3f1..758bfeb 100644 --- a/core/fpdfapi/cmaps/Japan1/Adobe-Japan1-UCS2_4.cpp +++ b/core/fpdfapi/cmaps/Japan1/Adobe-Japan1-UCS2_4.cpp
@@ -1,4 +1,4 @@ -// Copyright 2014 PDFium Authors. All rights reserved. +// Copyright 2014 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -6,7 +6,9 @@ #include "core/fpdfapi/cmaps/Japan1/cmaps_japan1.h" -const uint16_t g_FXCMAP_Japan1CID2Unicode_4[15444] = { +namespace fxcmap { + +const uint16_t kJapan1CID2Unicode_4[15444] = { 0xFFFD, 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, 0x0028, 0x0029, 0x002A, 0x002B, 0x002C, 0x002D, 0x002E, 0x002F, 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, 0x0038, 0x0039, @@ -1724,3 +1726,5 @@ 0x440C, 0x3E8A, 0xFFFD, 0xFFFD, 0x4BE8, 0xFFFD, 0x3EDA, 0x3B22, 0xFFFD, 0x457A, 0x4093, 0xFFFD, 0x4665, 0x4103, 0x4293, 0x46AE, 0x3488, 0xFFFD, }; + +} // namespace fxcmap
diff --git a/core/fpdfapi/cmaps/Japan1/EUC-H_1.cpp b/core/fpdfapi/cmaps/Japan1/EUC-H_1.cpp index ddb1bcf..c4675be 100644 --- a/core/fpdfapi/cmaps/Japan1/EUC-H_1.cpp +++ b/core/fpdfapi/cmaps/Japan1/EUC-H_1.cpp
@@ -1,4 +1,4 @@ -// Copyright 2014 PDFium Authors. All rights reserved. +// Copyright 2014 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -6,7 +6,9 @@ #include "core/fpdfapi/cmaps/Japan1/cmaps_japan1.h" -const uint16_t g_FXCMAP_EUC_H_1[120 * 3] = { +namespace fxcmap { + +const uint16_t kEUC_H_1[120 * 3] = { 0x0020, 0x007E, 0x00E7, 0x8EA0, 0x8EDF, 0x0146, 0xA1A1, 0xA1FE, 0x0279, 0xA2A1, 0xA2AE, 0x02D7, 0xA2BA, 0xA2C1, 0x02E5, 0xA2CA, 0xA2D0, 0x02ED, 0xA2DC, 0xA2EA, 0x02F4, 0xA2F2, 0xA2F9, 0x0303, 0xA2FE, 0xA2FE, 0x030B, @@ -48,3 +50,5 @@ 0xF0A1, 0xF0FE, 0x1BBA, 0xF1A1, 0xF1FE, 0x1C18, 0xF2A1, 0xF2FE, 0x1C76, 0xF3A1, 0xF3FE, 0x1CD4, 0xF4A1, 0xF4A4, 0x1D32, 0xF4A5, 0xF4A6, 0x205C, }; + +} // namespace fxcmap
diff --git a/core/fpdfapi/cmaps/Japan1/EUC-V_1.cpp b/core/fpdfapi/cmaps/Japan1/EUC-V_1.cpp index d5a70c6..c507656 100644 --- a/core/fpdfapi/cmaps/Japan1/EUC-V_1.cpp +++ b/core/fpdfapi/cmaps/Japan1/EUC-V_1.cpp
@@ -1,4 +1,4 @@ -// Copyright 2014 PDFium Authors. All rights reserved. +// Copyright 2014 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -6,7 +6,9 @@ #include "core/fpdfapi/cmaps/Japan1/cmaps_japan1.h" -const uint16_t g_FXCMAP_EUC_V_1[27 * 3] = { +namespace fxcmap { + +const uint16_t kEUC_V_1[27 * 3] = { 0xA1A2, 0xA1A3, 0x1ECF, 0xA1B1, 0xA1B2, 0x1ED1, 0xA1BC, 0xA1BE, 0x1ED3, 0xA1C1, 0xA1C5, 0x1ED6, 0xA1CA, 0xA1DB, 0x1EDB, 0xA1E1, 0xA1E1, 0x1EED, 0xA4A1, 0xA4A1, 0x1EEE, 0xA4A3, 0xA4A3, 0x1EEF, 0xA4A5, 0xA4A5, 0x1EF0, @@ -17,3 +19,5 @@ 0xA5C3, 0xA5C3, 0x1EFD, 0xA5E3, 0xA5E3, 0x1EFE, 0xA5E5, 0xA5E5, 0x1EFF, 0xA5E7, 0xA5E7, 0x1F00, 0xA5EE, 0xA5EE, 0x1F01, 0xA5F5, 0xA5F6, 0x1F02, }; + +} // namespace fxcmap
diff --git a/core/fpdfapi/cmaps/Japan1/Ext-RKSJ-H_2.cpp b/core/fpdfapi/cmaps/Japan1/Ext-RKSJ-H_2.cpp index b251c5d..80c0b48 100644 --- a/core/fpdfapi/cmaps/Japan1/Ext-RKSJ-H_2.cpp +++ b/core/fpdfapi/cmaps/Japan1/Ext-RKSJ-H_2.cpp
@@ -1,4 +1,4 @@ -// Copyright 2014 PDFium Authors. All rights reserved. +// Copyright 2014 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -6,7 +6,9 @@ #include "core/fpdfapi/cmaps/Japan1/cmaps_japan1.h" -const uint16_t g_FXCMAP_Ext_RKSJ_H_2[665 * 3] = { +namespace fxcmap { + +const uint16_t kExt_RKSJ_H_2[665 * 3] = { 0x0020, 0x007E, 0x00E7, 0x00A0, 0x00DF, 0x0146, 0x8140, 0x817E, 0x0279, 0x8180, 0x8188, 0x02B8, 0x8189, 0x8189, 0x1D36, 0x818A, 0x81AC, 0x02C2, 0x824F, 0x8258, 0x030C, 0x8260, 0x8279, 0x0316, 0x8281, 0x829A, 0x0330, @@ -230,3 +232,5 @@ 0xEE40, 0xEE7E, 0x2162, 0xEE80, 0xEEEC, 0x21A1, 0xEEEF, 0xEEF8, 0x1F9C, 0xEEF9, 0xEEF9, 0x02EF, 0xEEFA, 0xEEFC, 0x1F45, }; + +} // namespace fxcmap
diff --git a/core/fpdfapi/cmaps/Japan1/Ext-RKSJ-V_2.cpp b/core/fpdfapi/cmaps/Japan1/Ext-RKSJ-V_2.cpp index b62e5a5..f3833bc 100644 --- a/core/fpdfapi/cmaps/Japan1/Ext-RKSJ-V_2.cpp +++ b/core/fpdfapi/cmaps/Japan1/Ext-RKSJ-V_2.cpp
@@ -1,4 +1,4 @@ -// Copyright 2014 PDFium Authors. All rights reserved. +// Copyright 2014 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -6,7 +6,9 @@ #include "core/fpdfapi/cmaps/Japan1/cmaps_japan1.h" -const uint16_t g_FXCMAP_Ext_RKSJ_V_2[39 * 3] = { +namespace fxcmap { + +const uint16_t kExt_RKSJ_V_2[39 * 3] = { 0x8141, 0x8142, 0x1ECF, 0x8143, 0x8143, 0x204C, 0x8144, 0x8144, 0x2052, 0x814A, 0x814A, 0x2050, 0x814B, 0x814B, 0x204F, 0x815B, 0x815D, 0x1ED3, 0x8160, 0x8164, 0x1ED6, 0x8165, 0x8165, 0x2059, 0x8166, 0x8166, 0x2054, @@ -21,3 +23,5 @@ 0x8385, 0x8385, 0x1EFF, 0x8387, 0x8387, 0x1F00, 0x838E, 0x838E, 0x1F01, 0x8395, 0x8396, 0x1F02, 0x875F, 0x876E, 0x1F04, 0x8780, 0x8781, 0x1F14, }; + +} // namespace fxcmap
diff --git a/core/fpdfapi/cmaps/Japan1/H_1.cpp b/core/fpdfapi/cmaps/Japan1/H_1.cpp index be32b5c..be3694d 100644 --- a/core/fpdfapi/cmaps/Japan1/H_1.cpp +++ b/core/fpdfapi/cmaps/Japan1/H_1.cpp
@@ -1,4 +1,4 @@ -// Copyright 2014 PDFium Authors. All rights reserved. +// Copyright 2014 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -6,7 +6,9 @@ #include "core/fpdfapi/cmaps/Japan1/cmaps_japan1.h" -const uint16_t g_FXCMAP_H_1[118 * 3] = { +namespace fxcmap { + +const uint16_t kH_1[118 * 3] = { 0x2121, 0x217E, 0x0279, 0x2221, 0x222E, 0x02D7, 0x223A, 0x2241, 0x02E5, 0x224A, 0x2250, 0x02ED, 0x225C, 0x226A, 0x02F4, 0x2272, 0x2279, 0x0303, 0x227E, 0x227E, 0x030B, 0x2330, 0x2339, 0x030C, 0x2341, 0x235A, 0x0316, @@ -48,3 +50,5 @@ 0x7221, 0x727E, 0x1C76, 0x7321, 0x737E, 0x1CD4, 0x7421, 0x7424, 0x1D32, 0x7425, 0x7426, 0x205C, }; + +} // namespace fxcmap
diff --git a/core/fpdfapi/cmaps/Japan1/UniJIS-UCS2-HW-H_4.cpp b/core/fpdfapi/cmaps/Japan1/UniJIS-UCS2-HW-H_4.cpp index e03c139..aa8565d 100644 --- a/core/fpdfapi/cmaps/Japan1/UniJIS-UCS2-HW-H_4.cpp +++ b/core/fpdfapi/cmaps/Japan1/UniJIS-UCS2-HW-H_4.cpp
@@ -1,4 +1,4 @@ -// Copyright 2014 PDFium Authors. All rights reserved. +// Copyright 2014 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -6,7 +6,11 @@ #include "core/fpdfapi/cmaps/Japan1/cmaps_japan1.h" -const uint16_t g_FXCMAP_UniJIS_UCS2_HW_H_4[4 * 3] = { +namespace fxcmap { + +const uint16_t kUniJIS_UCS2_HW_H_4[4 * 3] = { 0x0020, 0x005B, 0x00E7, 0x005C, 0x005C, 0x220F, 0x005D, 0x007E, 0x0124, 0x00A5, 0x00A5, 0x0123, }; + +} // namespace fxcmap
diff --git a/core/fpdfapi/cmaps/Japan1/UniJIS-UCS2-HW-V_4.cpp b/core/fpdfapi/cmaps/Japan1/UniJIS-UCS2-HW-V_4.cpp index 3f3a2a4..aed1f63 100644 --- a/core/fpdfapi/cmaps/Japan1/UniJIS-UCS2-HW-V_4.cpp +++ b/core/fpdfapi/cmaps/Japan1/UniJIS-UCS2-HW-V_4.cpp
@@ -1,4 +1,4 @@ -// Copyright 2014 PDFium Authors. All rights reserved. +// Copyright 2014 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -6,7 +6,9 @@ #include "core/fpdfapi/cmaps/Japan1/cmaps_japan1.h" -const uint16_t g_FXCMAP_UniJIS_UCS2_HW_V_4[199 * 3] = { +namespace fxcmap { + +const uint16_t kUniJIS_UCS2_HW_V_4[199 * 3] = { 0x0020, 0x005B, 0x00E7, 0x005C, 0x005C, 0x220F, 0x005D, 0x007E, 0x0124, 0x00A5, 0x00A5, 0x0123, 0x00B0, 0x00B0, 0x204D, 0x2010, 0x2010, 0x1ED5, 0x2015, 0x2015, 0x1ED4, 0x2016, 0x2016, 0x1ED7, 0x2018, 0x2019, 0x2059, @@ -75,3 +77,5 @@ 0xFF5C, 0xFF5C, 0x1ED8, 0xFF5D, 0xFF5D, 0x1EE2, 0xFF5E, 0xFF5E, 0x1ED6, 0xFFE3, 0xFFE3, 0x1ED1, }; + +} // namespace fxcmap
diff --git a/core/fpdfapi/cmaps/Japan1/UniJIS-UCS2-H_4.cpp b/core/fpdfapi/cmaps/Japan1/UniJIS-UCS2-H_4.cpp index a8c8461..5496706 100644 --- a/core/fpdfapi/cmaps/Japan1/UniJIS-UCS2-H_4.cpp +++ b/core/fpdfapi/cmaps/Japan1/UniJIS-UCS2-H_4.cpp
@@ -1,4 +1,4 @@ -// Copyright 2014 PDFium Authors. All rights reserved. +// Copyright 2014 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -6,7 +6,9 @@ #include "core/fpdfapi/cmaps/Japan1/cmaps_japan1.h" -const uint16_t g_FXCMAP_UniJIS_UCS2_H_4[9772 * 2] = { +namespace fxcmap { + +const uint16_t kUniJIS_UCS2_H_4[9772 * 2] = { 0x0020, 0x0001, 0x0021, 0x0002, 0x0022, 0x0003, 0x0023, 0x0004, 0x0024, 0x0005, 0x0025, 0x0006, 0x0026, 0x0007, 0x0027, 0x0008, 0x0028, 0x0009, 0x0029, 0x000A, 0x002A, 0x000B, 0x002B, 0x000C, 0x002C, 0x000D, 0x002D, @@ -2180,3 +2182,5 @@ 0xFFE0, 0x02C9, 0xFFE1, 0x02CA, 0xFFE2, 0x02EF, 0xFFE3, 0x0289, 0xFFE4, 0x1F45, 0xFFE5, 0x02C7, 0xFFE8, 0x0143, }; + +} // namespace fxcmap
diff --git a/core/fpdfapi/cmaps/Japan1/UniJIS-UCS2-V_4.cpp b/core/fpdfapi/cmaps/Japan1/UniJIS-UCS2-V_4.cpp index 0e6b215..8c2cc89 100644 --- a/core/fpdfapi/cmaps/Japan1/UniJIS-UCS2-V_4.cpp +++ b/core/fpdfapi/cmaps/Japan1/UniJIS-UCS2-V_4.cpp
@@ -1,4 +1,4 @@ -// Copyright 2014 PDFium Authors. All rights reserved. +// Copyright 2014 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -6,7 +6,9 @@ #include "core/fpdfapi/cmaps/Japan1/cmaps_japan1.h" -const uint16_t g_FXCMAP_UniJIS_UCS2_V_4[251 * 2] = { +namespace fxcmap { + +const uint16_t kUniJIS_UCS2_V_4[251 * 2] = { 0x00B0, 0x204D, 0x2010, 0x1ED5, 0x2015, 0x1ED4, 0x2016, 0x1ED7, 0x2018, 0x2059, 0x2019, 0x205A, 0x201C, 0x2057, 0x201D, 0x2058, 0x2025, 0x1EDA, 0x2026, 0x1ED9, 0x2032, 0x2051, 0x2033, 0x205B, 0x2190, 0x02E2, 0x2191, @@ -64,3 +66,5 @@ 0xFF3B, 0x1EDF, 0xFF3D, 0x1EE0, 0xFF3F, 0x1ED2, 0xFF5B, 0x1EE1, 0xFF5C, 0x1ED8, 0xFF5D, 0x1EE2, 0xFF5E, 0x1ED6, 0xFFE3, 0x1ED1, }; + +} // namespace fxcmap
diff --git a/core/fpdfapi/cmaps/Japan1/V_1.cpp b/core/fpdfapi/cmaps/Japan1/V_1.cpp index 645e1ef..8fcc59f 100644 --- a/core/fpdfapi/cmaps/Japan1/V_1.cpp +++ b/core/fpdfapi/cmaps/Japan1/V_1.cpp
@@ -1,4 +1,4 @@ -// Copyright 2014 PDFium Authors. All rights reserved. +// Copyright 2014 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -6,7 +6,9 @@ #include "core/fpdfapi/cmaps/Japan1/cmaps_japan1.h" -const uint16_t g_FXCMAP_V_1[27 * 3] = { +namespace fxcmap { + +const uint16_t kV_1[27 * 3] = { 0x2122, 0x2123, 0x1ECF, 0x2131, 0x2132, 0x1ED1, 0x213C, 0x213E, 0x1ED3, 0x2141, 0x2145, 0x1ED6, 0x214A, 0x215B, 0x1EDB, 0x2161, 0x2161, 0x1EED, 0x2421, 0x2421, 0x1EEE, 0x2423, 0x2423, 0x1EEF, 0x2425, 0x2425, 0x1EF0, @@ -17,3 +19,5 @@ 0x2543, 0x2543, 0x1EFD, 0x2563, 0x2563, 0x1EFE, 0x2565, 0x2565, 0x1EFF, 0x2567, 0x2567, 0x1F00, 0x256E, 0x256E, 0x1F01, 0x2575, 0x2576, 0x1F02, }; + +} // namespace fxcmap
diff --git a/core/fpdfapi/cmaps/Japan1/cmaps_japan1.cpp b/core/fpdfapi/cmaps/Japan1/cmaps_japan1.cpp index 5a48c77..9475854 100644 --- a/core/fpdfapi/cmaps/Japan1/cmaps_japan1.cpp +++ b/core/fpdfapi/cmaps/Japan1/cmaps_japan1.cpp
@@ -1,4 +1,4 @@ -// Copyright 2014 PDFium Authors. All rights reserved. +// Copyright 2014 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -6,45 +6,39 @@ #include "core/fpdfapi/cmaps/Japan1/cmaps_japan1.h" -#include "core/fxcrt/fx_memory.h" +#include <iterator> -const FXCMAP_CMap g_FXCMAP_Japan1_cmaps[] = { - {"83pv-RKSJ-H", g_FXCMAP_83pv_RKSJ_H_1, nullptr, 222, 0, FXCMAP_CMap::Range, +namespace fxcmap { + +const CMap kJapan1_cmaps[] = { + {"83pv-RKSJ-H", k83pv_RKSJ_H_1, nullptr, 222, 0, CMap::Type::kRange, 0}, + {"90ms-RKSJ-H", k90ms_RKSJ_H_2, nullptr, 171, 0, CMap::Type::kRange, 0}, + {"90ms-RKSJ-V", k90ms_RKSJ_V_2, nullptr, 78, 0, CMap::Type::kRange, -1}, + {"90msp-RKSJ-H", k90msp_RKSJ_H_2, nullptr, 170, 0, CMap::Type::kRange, -2}, + {"90msp-RKSJ-V", k90msp_RKSJ_V_2, nullptr, 78, 0, CMap::Type::kRange, -1}, + {"90pv-RKSJ-H", k90pv_RKSJ_H_1, nullptr, 263, 0, CMap::Type::kRange, 0}, + {"Add-RKSJ-H", kAdd_RKSJ_H_1, nullptr, 635, 0, CMap::Type::kRange, 0}, + {"Add-RKSJ-V", kAdd_RKSJ_V_1, nullptr, 57, 0, CMap::Type::kRange, -1}, + {"EUC-H", kEUC_H_1, nullptr, 120, 0, CMap::Type::kRange, 0}, + {"EUC-V", kEUC_V_1, nullptr, 27, 0, CMap::Type::kRange, -1}, + {"Ext-RKSJ-H", kExt_RKSJ_H_2, nullptr, 665, 0, CMap::Type::kRange, -4}, + {"Ext-RKSJ-V", kExt_RKSJ_V_2, nullptr, 39, 0, CMap::Type::kRange, -1}, + {"H", kH_1, nullptr, 118, 0, CMap::Type::kRange, 0}, + {"V", kV_1, nullptr, 27, 0, CMap::Type::kRange, -1}, + {"UniJIS-UCS2-H", kUniJIS_UCS2_H_4, nullptr, 9772, 0, CMap::Type::kSingle, 0}, - {"90ms-RKSJ-H", g_FXCMAP_90ms_RKSJ_H_2, nullptr, 171, 0, FXCMAP_CMap::Range, - 0}, - {"90ms-RKSJ-V", g_FXCMAP_90ms_RKSJ_V_2, nullptr, 78, 0, FXCMAP_CMap::Range, + {"UniJIS-UCS2-V", kUniJIS_UCS2_V_4, nullptr, 251, 0, CMap::Type::kSingle, -1}, - {"90msp-RKSJ-H", g_FXCMAP_90msp_RKSJ_H_2, nullptr, 170, 0, - FXCMAP_CMap::Range, -2}, - {"90msp-RKSJ-V", g_FXCMAP_90msp_RKSJ_V_2, nullptr, 78, 0, - FXCMAP_CMap::Range, -1}, - {"90pv-RKSJ-H", g_FXCMAP_90pv_RKSJ_H_1, nullptr, 263, 0, FXCMAP_CMap::Range, + {"UniJIS-UCS2-HW-H", kUniJIS_UCS2_HW_H_4, nullptr, 4, 0, CMap::Type::kRange, + -2}, + {"UniJIS-UCS2-HW-V", kUniJIS_UCS2_HW_V_4, nullptr, 199, 0, + CMap::Type::kRange, -1}, + {"UniJIS-UTF16-H", kUniJIS_UCS2_H_4, nullptr, 9772, 0, CMap::Type::kSingle, 0}, - {"Add-RKSJ-H", g_FXCMAP_Add_RKSJ_H_1, nullptr, 635, 0, FXCMAP_CMap::Range, - 0}, - {"Add-RKSJ-V", g_FXCMAP_Add_RKSJ_V_1, nullptr, 57, 0, FXCMAP_CMap::Range, + {"UniJIS-UTF16-V", kUniJIS_UCS2_V_4, nullptr, 251, 0, CMap::Type::kSingle, -1}, - {"EUC-H", g_FXCMAP_EUC_H_1, nullptr, 120, 0, FXCMAP_CMap::Range, 0}, - {"EUC-V", g_FXCMAP_EUC_V_1, nullptr, 27, 0, FXCMAP_CMap::Range, -1}, - {"Ext-RKSJ-H", g_FXCMAP_Ext_RKSJ_H_2, nullptr, 665, 0, FXCMAP_CMap::Range, - -4}, - {"Ext-RKSJ-V", g_FXCMAP_Ext_RKSJ_V_2, nullptr, 39, 0, FXCMAP_CMap::Range, - -1}, - {"H", g_FXCMAP_H_1, nullptr, 118, 0, FXCMAP_CMap::Range, 0}, - {"V", g_FXCMAP_V_1, nullptr, 27, 0, FXCMAP_CMap::Range, -1}, - {"UniJIS-UCS2-H", g_FXCMAP_UniJIS_UCS2_H_4, nullptr, 9772, 0, - FXCMAP_CMap::Single, 0}, - {"UniJIS-UCS2-V", g_FXCMAP_UniJIS_UCS2_V_4, nullptr, 251, 0, - FXCMAP_CMap::Single, -1}, - {"UniJIS-UCS2-HW-H", g_FXCMAP_UniJIS_UCS2_HW_H_4, nullptr, 4, 0, - FXCMAP_CMap::Range, -2}, - {"UniJIS-UCS2-HW-V", g_FXCMAP_UniJIS_UCS2_HW_V_4, nullptr, 199, 0, - FXCMAP_CMap::Range, -1}, - {"UniJIS-UTF16-H", g_FXCMAP_UniJIS_UCS2_H_4, nullptr, 9772, 0, - FXCMAP_CMap::Single, 0}, - {"UniJIS-UTF16-V", g_FXCMAP_UniJIS_UCS2_V_4, nullptr, 251, 0, - FXCMAP_CMap::Single, -1}, }; -const size_t g_FXCMAP_Japan1_cmaps_size = FX_ArraySize(g_FXCMAP_Japan1_cmaps); +const size_t kJapan1_cmaps_size = std::size(kJapan1_cmaps); + +} // namespace fxcmap
diff --git a/core/fpdfapi/cmaps/Japan1/cmaps_japan1.h b/core/fpdfapi/cmaps/Japan1/cmaps_japan1.h index 267a9fc..45df22d 100644 --- a/core/fpdfapi/cmaps/Japan1/cmaps_japan1.h +++ b/core/fpdfapi/cmaps/Japan1/cmaps_japan1.h
@@ -1,4 +1,4 @@ -// Copyright 2015 PDFium Authors. All rights reserved. +// Copyright 2015 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -7,31 +7,38 @@ #ifndef CORE_FPDFAPI_CMAPS_JAPAN1_CMAPS_JAPAN1_H_ #define CORE_FPDFAPI_CMAPS_JAPAN1_CMAPS_JAPAN1_H_ +#include <stddef.h> +#include <stdint.h> + #include "core/fpdfapi/cmaps/fpdf_cmaps.h" -extern const uint16_t g_FXCMAP_83pv_RKSJ_H_1[]; -extern const uint16_t g_FXCMAP_90ms_RKSJ_H_2[]; -extern const uint16_t g_FXCMAP_90ms_RKSJ_V_2[]; -extern const uint16_t g_FXCMAP_90msp_RKSJ_H_2[]; -extern const uint16_t g_FXCMAP_90msp_RKSJ_V_2[]; -extern const uint16_t g_FXCMAP_90pv_RKSJ_H_1[]; -extern const uint16_t g_FXCMAP_Add_RKSJ_H_1[]; -extern const uint16_t g_FXCMAP_Add_RKSJ_V_1[]; -extern const uint16_t g_FXCMAP_EUC_H_1[]; -extern const uint16_t g_FXCMAP_EUC_V_1[]; -extern const uint16_t g_FXCMAP_Ext_RKSJ_H_2[]; -extern const uint16_t g_FXCMAP_Ext_RKSJ_V_2[]; -extern const uint16_t g_FXCMAP_H_1[]; -extern const uint16_t g_FXCMAP_V_1[]; -extern const uint16_t g_FXCMAP_UniJIS_UCS2_H_4[]; -extern const uint16_t g_FXCMAP_UniJIS_UCS2_V_4[]; -extern const uint16_t g_FXCMAP_UniJIS_UCS2_HW_H_4[]; -extern const uint16_t g_FXCMAP_UniJIS_UCS2_HW_V_4[]; -extern const uint16_t g_FXCMAP_UniJIS_UTF16_H_0[]; -extern const uint16_t g_FXCMAP_UniJIS_UTF16_H_0_DWord[]; -extern const uint16_t g_FXCMAP_UniJIS_UTF16_V_0[]; -extern const uint16_t g_FXCMAP_Japan1CID2Unicode_4[15444]; -extern const FXCMAP_CMap g_FXCMAP_Japan1_cmaps[]; -extern const size_t g_FXCMAP_Japan1_cmaps_size; +namespace fxcmap { + +extern const uint16_t k83pv_RKSJ_H_1[]; +extern const uint16_t k90ms_RKSJ_H_2[]; +extern const uint16_t k90ms_RKSJ_V_2[]; +extern const uint16_t k90msp_RKSJ_H_2[]; +extern const uint16_t k90msp_RKSJ_V_2[]; +extern const uint16_t k90pv_RKSJ_H_1[]; +extern const uint16_t kAdd_RKSJ_H_1[]; +extern const uint16_t kAdd_RKSJ_V_1[]; +extern const uint16_t kEUC_H_1[]; +extern const uint16_t kEUC_V_1[]; +extern const uint16_t kExt_RKSJ_H_2[]; +extern const uint16_t kExt_RKSJ_V_2[]; +extern const uint16_t kH_1[]; +extern const uint16_t kV_1[]; +extern const uint16_t kUniJIS_UCS2_H_4[]; +extern const uint16_t kUniJIS_UCS2_V_4[]; +extern const uint16_t kUniJIS_UCS2_HW_H_4[]; +extern const uint16_t kUniJIS_UCS2_HW_V_4[]; +extern const uint16_t kUniJIS_UTF16_H_0[]; +extern const uint16_t kUniJIS_UTF16_H_0_DWord[]; +extern const uint16_t kUniJIS_UTF16_V_0[]; +extern const uint16_t kJapan1CID2Unicode_4[15444]; +extern const CMap kJapan1_cmaps[]; +extern const size_t kJapan1_cmaps_size; + +} // namespace fxcmap #endif // CORE_FPDFAPI_CMAPS_JAPAN1_CMAPS_JAPAN1_H_
diff --git a/core/fpdfapi/cmaps/Korea1/Adobe-Korea1-UCS2_2.cpp b/core/fpdfapi/cmaps/Korea1/Adobe-Korea1-UCS2_2.cpp index 3f81ff9..e7657cf 100644 --- a/core/fpdfapi/cmaps/Korea1/Adobe-Korea1-UCS2_2.cpp +++ b/core/fpdfapi/cmaps/Korea1/Adobe-Korea1-UCS2_2.cpp
@@ -1,4 +1,4 @@ -// Copyright 2014 PDFium Authors. All rights reserved. +// Copyright 2014 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -6,7 +6,9 @@ #include "core/fpdfapi/cmaps/Korea1/cmaps_korea1.h" -const uint16_t g_FXCMAP_Korea1CID2Unicode_2[18352] = { +namespace fxcmap { + +const uint16_t kKorea1CID2Unicode_2[18352] = { 0xFFFD, 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, 0x0028, 0x0029, 0x002A, 0x002B, 0x002C, 0x002D, 0x002E, 0x002F, 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, 0x0038, 0x0039, @@ -2048,3 +2050,5 @@ 0x0077, 0x0078, 0x0079, 0x007A, 0x007B, 0x007C, 0x007D, 0x203E, 0x007E, 0x005C, }; + +} // namespace fxcmap
diff --git a/core/fpdfapi/cmaps/Korea1/KSC-EUC-H_0.cpp b/core/fpdfapi/cmaps/Korea1/KSC-EUC-H_0.cpp index cce7899..2ba31b4 100644 --- a/core/fpdfapi/cmaps/Korea1/KSC-EUC-H_0.cpp +++ b/core/fpdfapi/cmaps/Korea1/KSC-EUC-H_0.cpp
@@ -1,4 +1,4 @@ -// Copyright 2014 PDFium Authors. All rights reserved. +// Copyright 2014 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -6,7 +6,9 @@ #include "core/fpdfapi/cmaps/Korea1/cmaps_korea1.h" -const uint16_t g_FXCMAP_KSC_EUC_H_0[467 * 3] = { +namespace fxcmap { + +const uint16_t kKSC_EUC_H_0[467 * 3] = { 0x0020, 0x007E, 0x1F9E, 0xA1A1, 0xA1FE, 0x0065, 0xA2A1, 0xA2E5, 0x00C3, 0xA3A1, 0xA3FE, 0x0108, 0xA4A1, 0xA4D3, 0x0166, 0xA4D5, 0xA4FE, 0x0199, 0xA5A1, 0xA5AA, 0x01C3, 0xA5B0, 0xA5B9, 0x01CD, 0xA5C1, 0xA5D8, 0x01D7, @@ -164,3 +166,5 @@ 0xFBA1, 0xFBFE, 0x1E5F, 0xFCA1, 0xFCA8, 0x1EBD, 0xFCA9, 0xFCA9, 0x0EE7, 0xFCAA, 0xFCFE, 0x1EC5, 0xFDA1, 0xFDFE, 0x1F1A, }; + +} // namespace fxcmap
diff --git a/core/fpdfapi/cmaps/Korea1/KSC-EUC-V_0.cpp b/core/fpdfapi/cmaps/Korea1/KSC-EUC-V_0.cpp index 7408f9e..b166075 100644 --- a/core/fpdfapi/cmaps/Korea1/KSC-EUC-V_0.cpp +++ b/core/fpdfapi/cmaps/Korea1/KSC-EUC-V_0.cpp
@@ -1,4 +1,4 @@ -// Copyright 2014 PDFium Authors. All rights reserved. +// Copyright 2014 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -6,7 +6,9 @@ #include "core/fpdfapi/cmaps/Korea1/cmaps_korea1.h" -const uint16_t g_FXCMAP_KSC_EUC_V_0[16 * 3] = { +namespace fxcmap { + +const uint16_t kKSC_EUC_V_0[16 * 3] = { 0xA1A2, 0xA1A3, 0x1F78, 0xA1A5, 0xA1A5, 0x1F7A, 0xA1A6, 0xA1A6, 0x2080, 0xA1A9, 0xA1AB, 0x1F7B, 0xA1AD, 0xA1AD, 0x1F7E, 0xA1B2, 0xA1BD, 0x1F7F, 0xA1EB, 0xA1EB, 0x1F8B, 0xA3A1, 0xA3A1, 0x1F8C, @@ -14,3 +16,5 @@ 0x1F90, 0xA3BA, 0xA3BF, 0x1F91, 0xA3DB, 0xA3DB, 0x1F97, 0xA3DD, 0xA3DD, 0x1F98, 0xA3DF, 0xA3DF, 0x1F99, 0xA3FB, 0xA3FE, 0x1F9A, }; + +} // namespace fxcmap
diff --git a/core/fpdfapi/cmaps/Korea1/KSCms-UHC-HW-H_1.cpp b/core/fpdfapi/cmaps/Korea1/KSCms-UHC-HW-H_1.cpp index fbbdee8..161198d 100644 --- a/core/fpdfapi/cmaps/Korea1/KSCms-UHC-HW-H_1.cpp +++ b/core/fpdfapi/cmaps/Korea1/KSCms-UHC-HW-H_1.cpp
@@ -1,4 +1,4 @@ -// Copyright 2014 PDFium Authors. All rights reserved. +// Copyright 2014 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -6,7 +6,9 @@ #include "core/fpdfapi/cmaps/Korea1/cmaps_korea1.h" -const uint16_t g_FXCMAP_KSCms_UHC_HW_H_1[675 * 3] = { +namespace fxcmap { + +const uint16_t kKSCms_UHC_HW_H_1[675 * 3] = { 0x0020, 0x007E, 0x1F9E, 0x8141, 0x815A, 0x2475, 0x8161, 0x817A, 0x248F, 0x8181, 0x81FE, 0x24A9, 0x8241, 0x825A, 0x2527, 0x8261, 0x827A, 0x2541, 0x8281, 0x82FE, 0x255B, 0x8341, 0x835A, 0x25D9, 0x8361, 0x837A, 0x25F3, @@ -233,3 +235,5 @@ 0xFAE7, 0xFAFE, 0x1E47, 0xFBA1, 0xFBFE, 0x1E5F, 0xFCA1, 0xFCA8, 0x1EBD, 0xFCA9, 0xFCA9, 0x0EE7, 0xFCAA, 0xFCFE, 0x1EC5, 0xFDA1, 0xFDFE, 0x1F1A, }; + +} // namespace fxcmap
diff --git a/core/fpdfapi/cmaps/Korea1/KSCms-UHC-HW-V_1.cpp b/core/fpdfapi/cmaps/Korea1/KSCms-UHC-HW-V_1.cpp index 16ddafa..575a27d 100644 --- a/core/fpdfapi/cmaps/Korea1/KSCms-UHC-HW-V_1.cpp +++ b/core/fpdfapi/cmaps/Korea1/KSCms-UHC-HW-V_1.cpp
@@ -1,4 +1,4 @@ -// Copyright 2014 PDFium Authors. All rights reserved. +// Copyright 2014 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -6,7 +6,9 @@ #include "core/fpdfapi/cmaps/Korea1/cmaps_korea1.h" -const uint16_t g_FXCMAP_KSCms_UHC_HW_V_1[16 * 3] = { +namespace fxcmap { + +const uint16_t kKSCms_UHC_HW_V_1[16 * 3] = { 0xA1A2, 0xA1A3, 0x1F78, 0xA1A5, 0xA1A5, 0x1F7A, 0xA1A6, 0xA1A6, 0x2080, 0xA1A9, 0xA1AB, 0x1F7B, 0xA1AD, 0xA1AD, 0x1F7E, 0xA1B2, 0xA1BD, 0x1F7F, 0xA1EB, 0xA1EB, 0x1F8B, 0xA3A1, 0xA3A1, 0x1F8C, @@ -14,3 +16,5 @@ 0x1F90, 0xA3BA, 0xA3BF, 0x1F91, 0xA3DB, 0xA3DB, 0x1F97, 0xA3DD, 0xA3DD, 0x1F98, 0xA3DF, 0xA3DF, 0x1F99, 0xA3FB, 0xA3FE, 0x1F9A, }; + +} // namespace fxcmap
diff --git a/core/fpdfapi/cmaps/Korea1/KSCms-UHC-H_1.cpp b/core/fpdfapi/cmaps/Korea1/KSCms-UHC-H_1.cpp index 986c879..7d855c6 100644 --- a/core/fpdfapi/cmaps/Korea1/KSCms-UHC-H_1.cpp +++ b/core/fpdfapi/cmaps/Korea1/KSCms-UHC-H_1.cpp
@@ -1,4 +1,4 @@ -// Copyright 2014 PDFium Authors. All rights reserved. +// Copyright 2014 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -6,7 +6,9 @@ #include "core/fpdfapi/cmaps/Korea1/cmaps_korea1.h" -const uint16_t g_FXCMAP_KSCms_UHC_H_1[675 * 3] = { +namespace fxcmap { + +const uint16_t kKSCms_UHC_H_1[675 * 3] = { 0x0020, 0x007E, 0x0001, 0x8141, 0x815A, 0x2475, 0x8161, 0x817A, 0x248F, 0x8181, 0x81FE, 0x24A9, 0x8241, 0x825A, 0x2527, 0x8261, 0x827A, 0x2541, 0x8281, 0x82FE, 0x255B, 0x8341, 0x835A, 0x25D9, 0x8361, 0x837A, 0x25F3, @@ -233,3 +235,5 @@ 0xFAE7, 0xFAFE, 0x1E47, 0xFBA1, 0xFBFE, 0x1E5F, 0xFCA1, 0xFCA8, 0x1EBD, 0xFCA9, 0xFCA9, 0x0EE7, 0xFCAA, 0xFCFE, 0x1EC5, 0xFDA1, 0xFDFE, 0x1F1A, }; + +} // namespace fxcmap
diff --git a/core/fpdfapi/cmaps/Korea1/KSCms-UHC-V_1.cpp b/core/fpdfapi/cmaps/Korea1/KSCms-UHC-V_1.cpp index e040444..7b18417 100644 --- a/core/fpdfapi/cmaps/Korea1/KSCms-UHC-V_1.cpp +++ b/core/fpdfapi/cmaps/Korea1/KSCms-UHC-V_1.cpp
@@ -1,4 +1,4 @@ -// Copyright 2014 PDFium Authors. All rights reserved. +// Copyright 2014 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -6,7 +6,9 @@ #include "core/fpdfapi/cmaps/Korea1/cmaps_korea1.h" -const uint16_t g_FXCMAP_KSCms_UHC_V_1[16 * 3] = { +namespace fxcmap { + +const uint16_t kKSCms_UHC_V_1[16 * 3] = { 0xA1A2, 0xA1A3, 0x1F78, 0xA1A5, 0xA1A5, 0x1F7A, 0xA1A6, 0xA1A6, 0x2080, 0xA1A9, 0xA1AB, 0x1F7B, 0xA1AD, 0xA1AD, 0x1F7E, 0xA1B2, 0xA1BD, 0x1F7F, 0xA1EB, 0xA1EB, 0x1F8B, 0xA3A1, 0xA3A1, 0x1F8C, @@ -14,3 +16,5 @@ 0x1F90, 0xA3BA, 0xA3BF, 0x1F91, 0xA3DB, 0xA3DB, 0x1F97, 0xA3DD, 0xA3DD, 0x1F98, 0xA3DF, 0xA3DF, 0x1F99, 0xA3FB, 0xA3FE, 0x1F9A, }; + +} // namespace fxcmap
diff --git a/core/fpdfapi/cmaps/Korea1/KSCpc-EUC-H_0.cpp b/core/fpdfapi/cmaps/Korea1/KSCpc-EUC-H_0.cpp index 12fa16d..87e8aa5 100644 --- a/core/fpdfapi/cmaps/Korea1/KSCpc-EUC-H_0.cpp +++ b/core/fpdfapi/cmaps/Korea1/KSCpc-EUC-H_0.cpp
@@ -1,4 +1,4 @@ -// Copyright 2014 PDFium Authors. All rights reserved. +// Copyright 2014 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -6,7 +6,9 @@ #include "core/fpdfapi/cmaps/Korea1/cmaps_korea1.h" -const uint16_t g_FXCMAP_KSCpc_EUC_H_0[509 * 3] = { +namespace fxcmap { + +const uint16_t kKSCpc_EUC_H_0[509 * 3] = { 0x0020, 0x007E, 0x0001, 0x0081, 0x0083, 0x0060, 0x00FE, 0x00FF, 0x0063, 0xA141, 0xA17D, 0x1FFF, 0xA181, 0xA19A, 0x203C, 0xA19C, 0xA1A0, 0x2056, 0xA1A1, 0xA1A1, 0x0065, 0xA1A2, 0xA1A3, 0x205B, 0xA1A4, 0xA1FE, 0x0068, @@ -178,3 +180,5 @@ 0xFBA1, 0xFBFE, 0x1E5F, 0xFCA1, 0xFCA8, 0x1EBD, 0xFCA9, 0xFCA9, 0x0EE7, 0xFCAA, 0xFCFE, 0x1EC5, 0xFDA1, 0xFDFE, 0x1F1A, }; + +} // namespace fxcmap
diff --git a/core/fpdfapi/cmaps/Korea1/UniKS-UCS2-H_1.cpp b/core/fpdfapi/cmaps/Korea1/UniKS-UCS2-H_1.cpp index 8ed9fbe..0d8d3fc 100644 --- a/core/fpdfapi/cmaps/Korea1/UniKS-UCS2-H_1.cpp +++ b/core/fpdfapi/cmaps/Korea1/UniKS-UCS2-H_1.cpp
@@ -1,4 +1,4 @@ -// Copyright 2014 PDFium Authors. All rights reserved. +// Copyright 2014 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -6,7 +6,9 @@ #include "core/fpdfapi/cmaps/Korea1/cmaps_korea1.h" -const uint16_t g_FXCMAP_UniKS_UCS2_H_1[8394 * 3] = { +namespace fxcmap { + +const uint16_t kUniKS_UCS2_H_1[8394 * 3] = { 0x0020, 0x007E, 0x0001, 0x00A1, 0x00A1, 0x00D0, 0x00A4, 0x00A4, 0x00D6, 0x00A7, 0x00A7, 0x009B, 0x00A8, 0x00A8, 0x006B, 0x00AA, 0x00AA, 0x029C, 0x00AB, 0x00AB, 0x00B0, 0x00B0, 0x00B0, 0x008A, 0x00B1, 0x00B1, 0x0082, @@ -2806,3 +2808,5 @@ 0xFF5E, 0xFF5E, 0x0071, 0xFFE0, 0xFFE1, 0x008F, 0xFFE2, 0xFFE2, 0x00C2, 0xFFE3, 0xFFE3, 0x0165, 0xFFE5, 0xFFE5, 0x0091, 0xFFE6, 0xFFE6, 0x0143, }; + +} // namespace fxcmap
diff --git a/core/fpdfapi/cmaps/Korea1/UniKS-UCS2-V_1.cpp b/core/fpdfapi/cmaps/Korea1/UniKS-UCS2-V_1.cpp index 46759c5..a550b17 100644 --- a/core/fpdfapi/cmaps/Korea1/UniKS-UCS2-V_1.cpp +++ b/core/fpdfapi/cmaps/Korea1/UniKS-UCS2-V_1.cpp
@@ -1,4 +1,4 @@ -// Copyright 2014 PDFium Authors. All rights reserved. +// Copyright 2014 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -6,7 +6,9 @@ #include "core/fpdfapi/cmaps/Korea1/cmaps_korea1.h" -const uint16_t g_FXCMAP_UniKS_UCS2_V_1[18 * 3] = { +namespace fxcmap { + +const uint16_t kUniKS_UCS2_V_1[18 * 3] = { 0x2013, 0x2014, 0x1F7B, 0x2016, 0x2016, 0x1F7D, 0x2025, 0x2025, 0x1F7A, 0x3001, 0x3002, 0x1F78, 0x3008, 0x3011, 0x1F81, 0x3013, 0x3013, 0x1F8B, 0x3014, 0x3015, 0x1F7F, 0xFF01, 0xFF01, 0x1F8C, 0xFF08, 0xFF09, 0x1F8D, @@ -14,3 +16,5 @@ 0xFF3B, 0xFF3B, 0x1F97, 0xFF3D, 0xFF3D, 0x1F98, 0xFF3F, 0xFF3F, 0x1F99, 0xFF5B, 0xFF5D, 0x1F9A, 0xFF5E, 0xFF5E, 0x1F7E, 0xFFE3, 0xFFE3, 0x1F9D, }; + +} // namespace fxcmap
diff --git a/core/fpdfapi/cmaps/Korea1/UniKS-UTF16-H_0.cpp b/core/fpdfapi/cmaps/Korea1/UniKS-UTF16-H_0.cpp index 2101805..2d42617 100644 --- a/core/fpdfapi/cmaps/Korea1/UniKS-UTF16-H_0.cpp +++ b/core/fpdfapi/cmaps/Korea1/UniKS-UTF16-H_0.cpp
@@ -1,4 +1,4 @@ -// Copyright 2014 PDFium Authors. All rights reserved. +// Copyright 2014 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -6,7 +6,9 @@ #include "core/fpdfapi/cmaps/Korea1/cmaps_korea1.h" -const uint16_t g_FXCMAP_UniKS_UTF16_H_0[158 * 2] = { +namespace fxcmap { + +const uint16_t kUniKS_UTF16_H_0[158 * 2] = { 0x00A9, 0x0062, 0x2010, 0x0061, 0x20A9, 0x0060, 0x2F00, 0x193C, 0x2F04, 0x18EC, 0x2F06, 0x190D, 0x2F08, 0x192B, 0x2F0A, 0x194D, 0x2F0B, 0x1D4B, 0x2F11, 0x10AE, 0x2F12, 0x116A, 0x2F14, 0x143F, 0x2F17, 0x168C, 0x2F18, @@ -44,3 +46,5 @@ 0x2FD0, 0x1466, 0x2FD1, 0x1A7D, 0x2FD2, 0x1CBF, 0x2FD3, 0x11D3, 0x2FD4, 0x0F6A, }; + +} // namespace fxcmap
diff --git a/core/fpdfapi/cmaps/Korea1/cmaps_korea1.cpp b/core/fpdfapi/cmaps/Korea1/cmaps_korea1.cpp index 7362ff8..2109e04 100644 --- a/core/fpdfapi/cmaps/Korea1/cmaps_korea1.cpp +++ b/core/fpdfapi/cmaps/Korea1/cmaps_korea1.cpp
@@ -1,4 +1,4 @@ -// Copyright 2014 PDFium Authors. All rights reserved. +// Copyright 2014 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -6,29 +6,27 @@ #include "core/fpdfapi/cmaps/Korea1/cmaps_korea1.h" -#include "core/fxcrt/fx_memory.h" +#include <iterator> -const FXCMAP_CMap g_FXCMAP_Korea1_cmaps[] = { - {"KSC-EUC-H", g_FXCMAP_KSC_EUC_H_0, nullptr, 467, 0, FXCMAP_CMap::Range, 0}, - {"KSC-EUC-V", g_FXCMAP_KSC_EUC_V_0, nullptr, 16, 0, FXCMAP_CMap::Range, -1}, - {"KSCms-UHC-H", g_FXCMAP_KSCms_UHC_H_1, nullptr, 675, 0, FXCMAP_CMap::Range, - -2}, - {"KSCms-UHC-V", g_FXCMAP_KSCms_UHC_V_1, nullptr, 16, 0, FXCMAP_CMap::Range, +namespace fxcmap { + +const CMap kKorea1_cmaps[] = { + {"KSC-EUC-H", kKSC_EUC_H_0, nullptr, 467, 0, CMap::Type::kRange, 0}, + {"KSC-EUC-V", kKSC_EUC_V_0, nullptr, 16, 0, CMap::Type::kRange, -1}, + {"KSCms-UHC-H", kKSCms_UHC_H_1, nullptr, 675, 0, CMap::Type::kRange, -2}, + {"KSCms-UHC-V", kKSCms_UHC_V_1, nullptr, 16, 0, CMap::Type::kRange, -1}, + {"KSCms-UHC-HW-H", kKSCms_UHC_HW_H_1, nullptr, 675, 0, CMap::Type::kRange, + 0}, + {"KSCms-UHC-HW-V", kKSCms_UHC_HW_V_1, nullptr, 16, 0, CMap::Type::kRange, -1}, - {"KSCms-UHC-HW-H", g_FXCMAP_KSCms_UHC_HW_H_1, nullptr, 675, 0, - FXCMAP_CMap::Range, 0}, - {"KSCms-UHC-HW-V", g_FXCMAP_KSCms_UHC_HW_V_1, nullptr, 16, 0, - FXCMAP_CMap::Range, -1}, - {"KSCpc-EUC-H", g_FXCMAP_KSCpc_EUC_H_0, nullptr, 509, 0, FXCMAP_CMap::Range, - -6}, - {"UniKS-UCS2-H", g_FXCMAP_UniKS_UCS2_H_1, nullptr, 8394, 0, - FXCMAP_CMap::Range, 0}, - {"UniKS-UCS2-V", g_FXCMAP_UniKS_UCS2_V_1, nullptr, 18, 0, - FXCMAP_CMap::Range, -1}, - {"UniKS-UTF16-H", g_FXCMAP_UniKS_UTF16_H_0, nullptr, 158, 0, - FXCMAP_CMap::Single, -2}, - {"UniKS-UTF16-V", g_FXCMAP_UniKS_UCS2_V_1, nullptr, 18, 0, - FXCMAP_CMap::Range, -1}, + {"KSCpc-EUC-H", kKSCpc_EUC_H_0, nullptr, 509, 0, CMap::Type::kRange, -6}, + {"UniKS-UCS2-H", kUniKS_UCS2_H_1, nullptr, 8394, 0, CMap::Type::kRange, 0}, + {"UniKS-UCS2-V", kUniKS_UCS2_V_1, nullptr, 18, 0, CMap::Type::kRange, -1}, + {"UniKS-UTF16-H", kUniKS_UTF16_H_0, nullptr, 158, 0, CMap::Type::kSingle, + -2}, + {"UniKS-UTF16-V", kUniKS_UCS2_V_1, nullptr, 18, 0, CMap::Type::kRange, -1}, }; -const size_t g_FXCMAP_Korea1_cmaps_size = FX_ArraySize(g_FXCMAP_Korea1_cmaps); +const size_t kKorea1_cmaps_size = std::size(kKorea1_cmaps); + +} // namespace fxcmap
diff --git a/core/fpdfapi/cmaps/Korea1/cmaps_korea1.h b/core/fpdfapi/cmaps/Korea1/cmaps_korea1.h index d54d156..f75ded9 100644 --- a/core/fpdfapi/cmaps/Korea1/cmaps_korea1.h +++ b/core/fpdfapi/cmaps/Korea1/cmaps_korea1.h
@@ -1,4 +1,4 @@ -// Copyright 2015 PDFium Authors. All rights reserved. +// Copyright 2015 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -7,20 +7,27 @@ #ifndef CORE_FPDFAPI_CMAPS_KOREA1_CMAPS_KOREA1_H_ #define CORE_FPDFAPI_CMAPS_KOREA1_CMAPS_KOREA1_H_ +#include <stddef.h> +#include <stdint.h> + #include "core/fpdfapi/cmaps/fpdf_cmaps.h" -extern const uint16_t g_FXCMAP_KSC_EUC_H_0[]; -extern const uint16_t g_FXCMAP_KSC_EUC_V_0[]; -extern const uint16_t g_FXCMAP_KSCms_UHC_H_1[]; -extern const uint16_t g_FXCMAP_KSCms_UHC_V_1[]; -extern const uint16_t g_FXCMAP_KSCms_UHC_HW_H_1[]; -extern const uint16_t g_FXCMAP_KSCms_UHC_HW_V_1[]; -extern const uint16_t g_FXCMAP_KSCpc_EUC_H_0[]; -extern const uint16_t g_FXCMAP_UniKS_UCS2_H_1[]; -extern const uint16_t g_FXCMAP_UniKS_UCS2_V_1[]; -extern const uint16_t g_FXCMAP_UniKS_UTF16_H_0[]; -extern const uint16_t g_FXCMAP_Korea1CID2Unicode_2[18352]; -extern const FXCMAP_CMap g_FXCMAP_Korea1_cmaps[]; -extern const size_t g_FXCMAP_Korea1_cmaps_size; +namespace fxcmap { + +extern const uint16_t kKSC_EUC_H_0[]; +extern const uint16_t kKSC_EUC_V_0[]; +extern const uint16_t kKSCms_UHC_H_1[]; +extern const uint16_t kKSCms_UHC_V_1[]; +extern const uint16_t kKSCms_UHC_HW_H_1[]; +extern const uint16_t kKSCms_UHC_HW_V_1[]; +extern const uint16_t kKSCpc_EUC_H_0[]; +extern const uint16_t kUniKS_UCS2_H_1[]; +extern const uint16_t kUniKS_UCS2_V_1[]; +extern const uint16_t kUniKS_UTF16_H_0[]; +extern const uint16_t kKorea1CID2Unicode_2[18352]; +extern const CMap kKorea1_cmaps[]; +extern const size_t kKorea1_cmaps_size; + +} // namespace fxcmap #endif // CORE_FPDFAPI_CMAPS_KOREA1_CMAPS_KOREA1_H_
diff --git a/core/fpdfapi/cmaps/fpdf_cmaps.cpp b/core/fpdfapi/cmaps/fpdf_cmaps.cpp index 5c89faf..98187a1 100644 --- a/core/fpdfapi/cmaps/fpdf_cmaps.cpp +++ b/core/fpdfapi/cmaps/fpdf_cmaps.cpp
@@ -1,4 +1,4 @@ -// Copyright 2014 PDFium Authors. All rights reserved. +// Copyright 2014 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -8,6 +8,10 @@ #include <algorithm> +#include "third_party/base/check.h" + +namespace fxcmap { + namespace { struct SingleCmap { @@ -21,32 +25,23 @@ uint16_t cid; }; -const FXCMAP_CMap* FindNextCMap(const FXCMAP_CMap* pMap) { +const CMap* FindNextCMap(const CMap* pMap) { return pMap->m_UseOffset ? pMap + pMap->m_UseOffset : nullptr; } } // namespace -const FXCMAP_CMap* FindEmbeddedCMap(pdfium::span<const FXCMAP_CMap> pCMaps, - ByteStringView bsName) { - for (size_t i = 0; i < pCMaps.size(); i++) { - if (bsName == pCMaps[i].m_Name) - return &pCMaps[i]; - } - return nullptr; -} - -uint16_t CIDFromCharCode(const FXCMAP_CMap* pMap, uint32_t charcode) { - ASSERT(pMap); +uint16_t CIDFromCharCode(const CMap* pMap, uint32_t charcode) { + DCHECK(pMap); const uint16_t loword = static_cast<uint16_t>(charcode); if (charcode >> 16) { while (pMap) { if (pMap->m_pDWordMap) { - const FXCMAP_DWordCIDMap* begin = pMap->m_pDWordMap; + const DWordCIDMap* begin = pMap->m_pDWordMap; const auto* end = begin + pMap->m_DWordCount; const auto* found = std::lower_bound( begin, end, charcode, - [](const FXCMAP_DWordCIDMap& element, uint32_t charcode) { + [](const DWordCIDMap& element, uint32_t charcode) { uint16_t hiword = static_cast<uint16_t>(charcode >> 16); if (element.m_HiWord != hiword) return element.m_HiWord < hiword; @@ -64,7 +59,7 @@ while (pMap && pMap->m_pWordMap) { switch (pMap->m_WordMapType) { - case FXCMAP_CMap::Single: { + case CMap::Type::kSingle: { const auto* begin = reinterpret_cast<const SingleCmap*>(pMap->m_pWordMap); const auto* end = begin + pMap->m_WordCount; @@ -76,7 +71,7 @@ return found->cid; break; } - case FXCMAP_CMap::Range: { + case CMap::Type::kRange: { const auto* begin = reinterpret_cast<const RangeCmap*>(pMap->m_pWordMap); const auto* end = begin + pMap->m_WordCount; @@ -88,10 +83,6 @@ return found->cid + loword - found->low; break; } - default: { - NOTREACHED(); - break; - } } pMap = FindNextCMap(pMap); } @@ -99,16 +90,16 @@ return 0; } -uint32_t CharCodeFromCID(const FXCMAP_CMap* pMap, uint16_t cid) { +uint32_t CharCodeFromCID(const CMap* pMap, uint16_t cid) { // TODO(dsinclair): This should be checking both pMap->m_WordMap and // pMap->m_DWordMap. There was a second while() but it was never reached as // the first always returns. Investigate and determine how this should // really be working. (https://codereview.chromium.org/2235743003 removed the // second while loop.) - ASSERT(pMap); + DCHECK(pMap); while (pMap) { switch (pMap->m_WordMapType) { - case FXCMAP_CMap::Single: { + case CMap::Type::kSingle: { const auto* pCur = reinterpret_cast<const SingleCmap*>(pMap->m_pWordMap); const auto* pEnd = pCur + pMap->m_WordCount; @@ -119,7 +110,7 @@ } break; } - case FXCMAP_CMap::Range: { + case CMap::Type::kRange: { const auto* pCur = reinterpret_cast<const RangeCmap*>(pMap->m_pWordMap); const auto* pEnd = pCur + pMap->m_WordCount; while (pCur < pEnd) { @@ -129,12 +120,10 @@ } break; } - default: { - NOTREACHED(); - break; - } } pMap = FindNextCMap(pMap); } return 0; } + +} // namespace fxcmap
diff --git a/core/fpdfapi/cmaps/fpdf_cmaps.h b/core/fpdfapi/cmaps/fpdf_cmaps.h index 2c7548a..079459a 100644 --- a/core/fpdfapi/cmaps/fpdf_cmaps.h +++ b/core/fpdfapi/cmaps/fpdf_cmaps.h
@@ -1,4 +1,4 @@ -// Copyright 2014 PDFium Authors. All rights reserved. +// Copyright 2014 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -9,31 +9,30 @@ #include <stdint.h> -#include "core/fxcrt/fx_string.h" -#include "third_party/base/span.h" +namespace fxcmap { -struct FXCMAP_DWordCIDMap { +struct DWordCIDMap { uint16_t m_HiWord; uint16_t m_LoWordLow; uint16_t m_LoWordHigh; uint16_t m_CID; }; -struct FXCMAP_CMap { - enum MapType : uint8_t { Single, Range }; +struct CMap { + enum class Type : bool { kSingle, kRange }; - const char* m_Name; // Raw, POD struct. - const uint16_t* m_pWordMap; // Raw, POD struct. - const FXCMAP_DWordCIDMap* m_pDWordMap; // Raw, POD struct. + const char* m_Name; // Raw, POD struct. + const uint16_t* m_pWordMap; // Raw, POD struct. + const DWordCIDMap* m_pDWordMap; // Raw, POD struct. uint16_t m_WordCount; uint16_t m_DWordCount; - MapType m_WordMapType; + Type m_WordMapType; int8_t m_UseOffset; }; -const FXCMAP_CMap* FindEmbeddedCMap(pdfium::span<const FXCMAP_CMap> pCMaps, - ByteStringView name); -uint16_t CIDFromCharCode(const FXCMAP_CMap* pMap, uint32_t charcode); -uint32_t CharCodeFromCID(const FXCMAP_CMap* pMap, uint16_t cid); +uint16_t CIDFromCharCode(const CMap* pMap, uint32_t charcode); +uint32_t CharCodeFromCID(const CMap* pMap, uint16_t cid); + +} // namespace fxcmap #endif // CORE_FPDFAPI_CMAPS_FPDF_CMAPS_H_
diff --git a/core/fpdfapi/edit/Android.bp b/core/fpdfapi/edit/Android.bp index 1822b06..6b70ca8 100644 --- a/core/fpdfapi/edit/Android.bp +++ b/core/fpdfapi/edit/Android.bp
@@ -13,11 +13,8 @@ visibility: ["//external/pdfium:__subpackages__"], - header_libs: [ - "libpdfium-constants", - ], - static_libs: [ + "libpdfium-constants", "libpdfium-fxcrt", "libpdfium-font", "libpdfium-page",
diff --git a/core/fpdfapi/edit/BUILD.gn b/core/fpdfapi/edit/BUILD.gn index cda86e63..721dff8 100644 --- a/core/fpdfapi/edit/BUILD.gn +++ b/core/fpdfapi/edit/BUILD.gn
@@ -1,4 +1,4 @@ -# Copyright 2018 The PDFium Authors. All rights reserved. +# Copyright 2018 The PDFium Authors # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. @@ -18,7 +18,10 @@ "cpdf_stringarchivestream.cpp", "cpdf_stringarchivestream.h", ] - configs += [ "../../../:pdfium_core_config" ] + configs += [ + "../../../:pdfium_strict_config", + "../../../:pdfium_noshorten_config", + ] deps = [ "../../../constants", "../../../third_party:skia_shared", @@ -37,7 +40,9 @@ "../../fxge", "../font", "../page", + "../page:unit_test_support", "../parser", + "../parser:unit_test_support", "../render", ] pdfium_root_dir = "../../../"
diff --git a/core/fpdfapi/edit/cpdf_contentstream_write_utils.cpp b/core/fpdfapi/edit/cpdf_contentstream_write_utils.cpp index 28165b1..af6a169 100644 --- a/core/fpdfapi/edit/cpdf_contentstream_write_utils.cpp +++ b/core/fpdfapi/edit/cpdf_contentstream_write_utils.cpp
@@ -1,9 +1,11 @@ -// Copyright 2019 PDFium Authors. All rights reserved. +// Copyright 2019 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "core/fpdfapi/edit/cpdf_contentstream_write_utils.h" +#include <ostream> + #include "third_party/skia_shared/SkFloatToDecimal.h" std::ostream& WriteFloat(std::ostream& stream, float value) { @@ -13,18 +15,26 @@ return stream; } -std::ostream& operator<<(std::ostream& ar, const CFX_Matrix& matrix) { - WriteFloat(ar, matrix.a) << " "; - WriteFloat(ar, matrix.b) << " "; - WriteFloat(ar, matrix.c) << " "; - WriteFloat(ar, matrix.d) << " "; - WriteFloat(ar, matrix.e) << " "; - WriteFloat(ar, matrix.f); - return ar; +std::ostream& WriteMatrix(std::ostream& stream, const CFX_Matrix& matrix) { + WriteFloat(stream, matrix.a) << " "; + WriteFloat(stream, matrix.b) << " "; + WriteFloat(stream, matrix.c) << " "; + WriteFloat(stream, matrix.d) << " "; + WriteFloat(stream, matrix.e) << " "; + WriteFloat(stream, matrix.f); + return stream; } -std::ostream& operator<<(std::ostream& ar, const CFX_PointF& point) { - WriteFloat(ar, point.x) << " "; - WriteFloat(ar, point.y); - return ar; +std::ostream& WritePoint(std::ostream& stream, const CFX_PointF& point) { + WriteFloat(stream, point.x) << " "; + WriteFloat(stream, point.y); + return stream; +} + +std::ostream& WriteRect(std::ostream& stream, const CFX_FloatRect& rect) { + WriteFloat(stream, rect.left) << " "; + WriteFloat(stream, rect.bottom) << " "; + WriteFloat(stream, rect.Width()) << " "; + WriteFloat(stream, rect.Height()); + return stream; }
diff --git a/core/fpdfapi/edit/cpdf_contentstream_write_utils.h b/core/fpdfapi/edit/cpdf_contentstream_write_utils.h index 3e14c9f..2440d92 100644 --- a/core/fpdfapi/edit/cpdf_contentstream_write_utils.h +++ b/core/fpdfapi/edit/cpdf_contentstream_write_utils.h
@@ -1,16 +1,17 @@ -// Copyright 2019 PDFium Authors. All rights reserved. +// Copyright 2019 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #ifndef CORE_FPDFAPI_EDIT_CPDF_CONTENTSTREAM_WRITE_UTILS_H_ #define CORE_FPDFAPI_EDIT_CPDF_CONTENTSTREAM_WRITE_UTILS_H_ -#include <ostream> +#include <iosfwd> #include "core/fxcrt/fx_coordinates.h" std::ostream& WriteFloat(std::ostream& stream, float value); -std::ostream& operator<<(std::ostream& ar, const CFX_Matrix& matrix); -std::ostream& operator<<(std::ostream& ar, const CFX_PointF& point); +std::ostream& WriteMatrix(std::ostream& stream, const CFX_Matrix& matrix); +std::ostream& WritePoint(std::ostream& stream, const CFX_PointF& point); +std::ostream& WriteRect(std::ostream& stream, const CFX_FloatRect& rect); #endif // CORE_FPDFAPI_EDIT_CPDF_CONTENTSTREAM_WRITE_UTILS_H_
diff --git a/core/fpdfapi/edit/cpdf_creator.cpp b/core/fpdfapi/edit/cpdf_creator.cpp index 65ddc45..9a2b88b 100644 --- a/core/fpdfapi/edit/cpdf_creator.cpp +++ b/core/fpdfapi/edit/cpdf_creator.cpp
@@ -1,4 +1,4 @@ -// Copyright 2014 PDFium Authors. All rights reserved. +// Copyright 2014 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -6,7 +6,11 @@ #include "core/fpdfapi/edit/cpdf_creator.h" +#include <stdint.h> + #include <algorithm> +#include <set> +#include <utility> #include "core/fpdfapi/parser/cpdf_array.h" #include "core/fpdfapi/parser/cpdf_crypto_handler.h" @@ -18,14 +22,16 @@ #include "core/fpdfapi/parser/cpdf_parser.h" #include "core/fpdfapi/parser/cpdf_security_handler.h" #include "core/fpdfapi/parser/cpdf_string.h" -#include "core/fpdfapi/parser/cpdf_syntax_parser.h" #include "core/fpdfapi/parser/fpdf_parser_utility.h" +#include "core/fpdfapi/parser/object_tree_traversal_util.h" +#include "core/fxcrt/data_vector.h" #include "core/fxcrt/fx_extension.h" -#include "core/fxcrt/fx_memory_wrappers.h" #include "core/fxcrt/fx_random.h" #include "core/fxcrt/fx_safe_types.h" -#include "third_party/base/ptr_util.h" -#include "third_party/base/stl_util.h" +#include "core/fxcrt/span_util.h" +#include "core/fxcrt/stl_util.h" +#include "third_party/base/check.h" +#include "third_party/base/containers/contains.h" namespace { @@ -33,33 +39,27 @@ class CFX_FileBufferArchive final : public IFX_ArchiveStream { public: - explicit CFX_FileBufferArchive( - const RetainPtr<IFX_RetainableWriteStream>& file); + explicit CFX_FileBufferArchive(RetainPtr<IFX_RetainableWriteStream> file); ~CFX_FileBufferArchive() override; - bool WriteBlock(const void* pBuf, size_t size) override; - bool WriteByte(uint8_t byte) override; - bool WriteDWord(uint32_t i) override; - bool WriteString(ByteStringView str) override; - + bool WriteBlock(pdfium::span<const uint8_t> buffer) override; FX_FILESIZE CurrentOffset() const override { return offset_; } private: bool Flush(); - FX_FILESIZE offset_; - size_t current_length_; - std::vector<uint8_t, FxAllocAllocator<uint8_t>> buffer_; - RetainPtr<IFX_RetainableWriteStream> backing_file_; + FX_FILESIZE offset_ = 0; + DataVector<uint8_t> buffer_; + pdfium::span<uint8_t> available_; + RetainPtr<IFX_RetainableWriteStream> const backing_file_; }; CFX_FileBufferArchive::CFX_FileBufferArchive( - const RetainPtr<IFX_RetainableWriteStream>& file) - : offset_(0), - current_length_(0), - buffer_(kArchiveBufferSize), - backing_file_(file) { - ASSERT(file); + RetainPtr<IFX_RetainableWriteStream> file) + : buffer_(kArchiveBufferSize), + available_(buffer_), + backing_file_(std::move(file)) { + DCHECK(backing_file_); } CFX_FileBufferArchive::~CFX_FileBufferArchive() { @@ -67,35 +67,29 @@ } bool CFX_FileBufferArchive::Flush() { - size_t nRemaining = current_length_; - current_length_ = 0; - if (!backing_file_) - return false; - if (!nRemaining) + size_t nUsed = buffer_.size() - available_.size(); + available_ = pdfium::make_span(buffer_); + if (!nUsed) return true; - return backing_file_->WriteBlock(buffer_.data(), nRemaining); + return backing_file_->WriteBlock(available_.first(nUsed)); } -bool CFX_FileBufferArchive::WriteBlock(const void* pBuf, size_t size) { - ASSERT(pBuf); - ASSERT(size > 0); +bool CFX_FileBufferArchive::WriteBlock(pdfium::span<const uint8_t> buffer) { + if (buffer.empty()) + return true; - const uint8_t* buffer = reinterpret_cast<const uint8_t*>(pBuf); - size_t temp_size = size; - while (temp_size) { - size_t buf_size = std::min(kArchiveBufferSize - current_length_, temp_size); - memcpy(buffer_.data() + current_length_, buffer, buf_size); - - current_length_ += buf_size; - if (current_length_ == kArchiveBufferSize && !Flush()) + pdfium::span<const uint8_t> src_span = buffer; + while (!src_span.empty()) { + size_t copy_size = std::min(available_.size(), src_span.size()); + fxcrt::spancpy(available_, src_span.first(copy_size)); + src_span = src_span.subspan(copy_size); + available_ = available_.subspan(copy_size); + if (available_.empty() && !Flush()) return false; - - temp_size -= buf_size; - buffer += buf_size; } FX_SAFE_FILESIZE safe_offset = offset_; - safe_offset += size; + safe_offset += buffer.size(); if (!safe_offset.IsValid()) return false; @@ -103,20 +97,6 @@ return true; } -bool CFX_FileBufferArchive::WriteByte(uint8_t byte) { - return WriteBlock(&byte, 1); -} - -bool CFX_FileBufferArchive::WriteDWord(uint32_t i) { - char buf[32]; - FXSYS_itoa(i, buf, 10); - return WriteBlock(buf, strlen(buf)); -} - -bool CFX_FileBufferArchive::WriteString(ByteStringView str) { - return WriteBlock(str.raw_str(), str.GetLength()); -} - ByteString GenerateFileID(uint32_t dwSeed1, uint32_t dwSeed2) { uint32_t buffer[4]; void* pContext1 = FX_Random_MT_Start(dwSeed1); @@ -141,15 +121,15 @@ } // namespace CPDF_Creator::CPDF_Creator(CPDF_Document* pDoc, - const RetainPtr<IFX_RetainableWriteStream>& archive) + RetainPtr<IFX_RetainableWriteStream> archive) : m_pDocument(pDoc), m_pParser(pDoc->GetParser()), m_pEncryptDict(m_pParser ? m_pParser->GetEncryptDict() : nullptr), m_pSecurityHandler(m_pParser ? m_pParser->GetSecurityHandler() : nullptr), m_dwLastObjNum(m_pDocument->GetLastObjNum()), - m_Archive(pdfium::MakeUnique<CFX_FileBufferArchive>(archive)) {} + m_Archive(std::make_unique<CFX_FileBufferArchive>(std::move(archive))) {} -CPDF_Creator::~CPDF_Creator() {} +CPDF_Creator::~CPDF_Creator() = default; bool CPDF_Creator::WriteIndirectObj(uint32_t objnum, const CPDF_Object* pObj) { if (!m_Archive->WriteDWord(objnum) || !m_Archive->WriteString(" 0 obj\r\n")) @@ -157,7 +137,7 @@ std::unique_ptr<CPDF_Encryptor> encryptor; if (GetCryptoHandler() && pObj != m_pEncryptDict) - encryptor = pdfium::MakeUnique<CPDF_Encryptor>(GetCryptoHandler(), objnum); + encryptor = std::make_unique<CPDF_Encryptor>(GetCryptoHandler(), objnum); if (!pObj->WriteTo(m_Archive.get(), encryptor.get())) return false; @@ -172,12 +152,12 @@ m_ObjectOffsets[objnum] = m_Archive->CurrentOffset(); bool bExistInMap = !!m_pDocument->GetIndirectObject(objnum); - CPDF_Object* pObj = m_pDocument->GetOrParseIndirectObject(objnum); + RetainPtr<CPDF_Object> pObj = m_pDocument->GetOrParseIndirectObject(objnum); if (!pObj) { m_ObjectOffsets.erase(objnum); return true; } - if (!WriteIndirectObj(pObj->GetObjNum(), pObj)) + if (!WriteIndirectObj(pObj->GetObjNum(), pObj.Get())) return false; if (!bExistInMap) m_pDocument->DeleteIndirectObject(objnum); @@ -185,13 +165,30 @@ } bool CPDF_Creator::WriteOldObjs() { - uint32_t nLastObjNum = m_pParser->GetLastObjNum(); - if (!m_pParser->IsValidObjectNumber(nLastObjNum)) + const uint32_t nLastObjNum = m_pParser->GetLastObjNum(); + if (!m_pParser->IsValidObjectNumber(nLastObjNum)) { return true; + } + if (m_CurObjNum > nLastObjNum) { + return true; + } + const std::set<uint32_t> objects_with_refs = + GetObjectsWithReferences(m_pDocument); + uint32_t last_object_number_written = 0; for (uint32_t objnum = m_CurObjNum; objnum <= nLastObjNum; ++objnum) { - if (!WriteOldIndirectObject(objnum)) + if (!pdfium::Contains(objects_with_refs, objnum)) { + continue; + } + if (!WriteOldIndirectObject(objnum)) { return false; + } + last_object_number_written = objnum; + } + // If there are no new objects to write, then adjust `m_dwLastObjNum` if + // needed to reflect the actual last object number. + if (m_NewObjNumArray.empty()) { + m_dwLastObjNum = last_object_number_written; } return true; } @@ -199,12 +196,12 @@ bool CPDF_Creator::WriteNewObjs() { for (size_t i = m_CurObjNum; i < m_NewObjNumArray.size(); ++i) { uint32_t objnum = m_NewObjNumArray[i]; - CPDF_Object* pObj = m_pDocument->GetIndirectObject(objnum); + RetainPtr<const CPDF_Object> pObj = m_pDocument->GetIndirectObject(objnum); if (!pObj) continue; m_ObjectOffsets[objnum] = m_Archive->CurrentOffset(); - if (!WriteIndirectObj(pObj->GetObjNum(), pObj)) + if (!WriteIndirectObj(pObj->GetObjNum(), pObj.Get())) return false; } return true; @@ -228,13 +225,11 @@ } CPDF_Creator::Stage CPDF_Creator::WriteDoc_Stage1() { - ASSERT(m_iStage > Stage::kInvalid || m_iStage < Stage::kInitWriteObjs20); + DCHECK(m_iStage > Stage::kInvalid || m_iStage < Stage::kInitWriteObjs20); if (m_iStage == Stage::kInit0) { if (!m_pParser || (m_bSecurityChanged && m_IsOriginal)) m_IsIncremental = false; - const CPDF_Dictionary* pDict = m_pDocument->GetRoot(); - m_pMetadata.Reset(pDict ? pDict->GetDirectObjectFor("Metadata") : nullptr); m_iStage = Stage::kWriteHeader10; } if (m_iStage == Stage::kWriteHeader10) { @@ -254,26 +249,14 @@ } m_iStage = Stage::kInitWriteObjs20; } else { - m_SavedOffset = m_pParser->GetSyntax()->GetDocumentSize(); + m_SavedOffset = m_pParser->GetDocumentSize(); m_iStage = Stage::kWriteIncremental15; } } if (m_iStage == Stage::kWriteIncremental15) { if (m_IsOriginal && m_SavedOffset > 0) { - static constexpr FX_FILESIZE kBufferSize = 4096; - std::vector<uint8_t, FxAllocAllocator<uint8_t>> buffer(kBufferSize); - FX_FILESIZE src_size = m_SavedOffset; - m_pParser->GetSyntax()->SetPos(0); - while (src_size) { - const FX_FILESIZE block_size = std::min(kBufferSize, src_size); - if (!m_pParser->GetSyntax()->ReadBlock(buffer.data(), block_size)) { - return Stage::kInvalid; - } - if (!m_Archive->WriteBlock(buffer.data(), block_size)) - return Stage::kInvalid; - - src_size -= block_size; - } + if (!m_pParser->WriteToArchive(m_Archive.get(), m_SavedOffset)) + return Stage::kInvalid; } if (m_IsOriginal && m_pParser->GetLastXRefOffset() == 0) { for (uint32_t num = 0; num <= m_pParser->GetLastObjNum(); ++num) { @@ -290,7 +273,7 @@ } CPDF_Creator::Stage CPDF_Creator::WriteDoc_Stage2() { - ASSERT(m_iStage >= Stage::kInitWriteObjs20 || + DCHECK(m_iStage >= Stage::kInitWriteObjs20 || m_iStage < Stage::kInitWriteXRefs80); if (m_iStage == Stage::kInitWriteObjs20) { if (!m_IsIncremental && m_pParser) { @@ -333,7 +316,7 @@ } CPDF_Creator::Stage CPDF_Creator::WriteDoc_Stage3() { - ASSERT(m_iStage >= Stage::kInitWriteXRefs80 || + DCHECK(m_iStage >= Stage::kInitWriteXRefs80 || m_iStage < Stage::kWriteTrailerAndFinish90); uint32_t dwLastObjNum = m_dwLastObjNum; @@ -342,7 +325,7 @@ if (!m_IsIncremental || !m_pParser->IsXRefStream()) { if (!m_IsIncremental || m_pParser->GetLastXRefOffset() == 0) { ByteString str; - str = pdfium::ContainsKey(m_ObjectOffsets, 1) + str = pdfium::Contains(m_ObjectOffsets, 1) ? "xref\r\n" : "xref\r\n0 1\r\n0000000000 65535 f\r\n"; if (!m_Archive->WriteString(str.AsStringView())) @@ -366,14 +349,14 @@ uint32_t i = m_CurObjNum; uint32_t j; while (i <= dwLastObjNum) { - while (i <= dwLastObjNum && !pdfium::ContainsKey(m_ObjectOffsets, i)) + while (i <= dwLastObjNum && !pdfium::Contains(m_ObjectOffsets, i)) i++; if (i > dwLastObjNum) break; j = i; - while (j <= dwLastObjNum && pdfium::ContainsKey(m_ObjectOffsets, j)) + while (j <= dwLastObjNum && pdfium::Contains(m_ObjectOffsets, j)) j++; if (i == 1) @@ -396,7 +379,7 @@ } if (m_iStage == Stage::kWriteXrefsIncremental82) { ByteString str; - uint32_t iCount = pdfium::CollectionSize<uint32_t>(m_NewObjNumArray); + uint32_t iCount = fxcrt::CollectionSize<uint32_t>(m_NewObjNumArray); uint32_t i = m_CurObjNum; while (i < iCount) { size_t j = i; @@ -431,7 +414,7 @@ } CPDF_Creator::Stage CPDF_Creator::WriteDoc_Stage4() { - ASSERT(m_iStage >= Stage::kWriteTrailerAndFinish90); + DCHECK(m_iStage >= Stage::kWriteTrailerAndFinish90); bool bXRefStream = m_IsIncremental && m_pParser->IsXRefStream(); if (!bXRefStream) { @@ -445,11 +428,10 @@ } if (m_pParser) { - RetainPtr<CPDF_Dictionary> p = m_pParser->GetCombinedTrailer(); - CPDF_DictionaryLocker locker(p.Get()); + CPDF_DictionaryLocker locker(m_pParser->GetCombinedTrailer()); for (const auto& it : locker) { const ByteString& key = it.first; - CPDF_Object* pValue = it.second.Get(); + const RetainPtr<CPDF_Object>& pValue = it.second; if (key == "Encrypt" || key == "Size" || key == "Filter" || key == "Index" || key == "Length" || key == "Prev" || key == "W" || key == "XRefStm" || key == "ID" || key == "DecodeParms" || @@ -497,13 +479,7 @@ if (m_IsIncremental) { FX_FILESIZE prev = m_pParser->GetLastXRefOffset(); if (prev) { - if (!m_Archive->WriteString("/Prev ")) - return Stage::kInvalid; - - char offset_buf[20]; - memset(offset_buf, 0, sizeof(offset_buf)); - FXSYS_i64toa(prev, offset_buf, 10); - if (!m_Archive->WriteBlock(offset_buf, strlen(offset_buf))) + if (!m_Archive->WriteString("/Prev ") || !m_Archive->WriteFilesize(prev)) return Stage::kInvalid; } } @@ -522,7 +498,7 @@ if (m_IsIncremental && m_pParser && m_pParser->GetLastXRefOffset() == 0) { uint32_t i = 0; for (i = 0; i < m_dwLastObjNum; i++) { - if (!pdfium::ContainsKey(m_ObjectOffsets, i)) + if (!pdfium::Contains(m_ObjectOffsets, i)) continue; if (!m_Archive->WriteDWord(i) || !m_Archive->WriteString(" 1 ")) return Stage::kInvalid; @@ -540,8 +516,8 @@ return Stage::kInvalid; } } else { - size_t count = m_NewObjNumArray.size(); - size_t i = 0; + int count = fxcrt::CollectionSize<int>(m_NewObjNumArray); + int i = 0; for (i = 0; i < count; i++) { if (!m_Archive->WriteDWord(m_NewObjNumArray[i]) || !m_Archive->WriteString(" 1 ")) { @@ -562,13 +538,8 @@ return Stage::kInvalid; } - if (!m_Archive->WriteString("\r\nstartxref\r\n")) - return Stage::kInvalid; - - char offset_buf[20]; - memset(offset_buf, 0, sizeof(offset_buf)); - FXSYS_i64toa(m_XrefStart, offset_buf, 10); - if (!m_Archive->WriteBlock(offset_buf, strlen(offset_buf)) || + if (!m_Archive->WriteString("\r\nstartxref\r\n") || + !m_Archive->WriteFilesize(m_XrefStart) || !m_Archive->WriteString("\r\n%%EOF\r\n")) { return Stage::kInvalid; } @@ -591,37 +562,39 @@ } void CPDF_Creator::InitID() { - ASSERT(!m_pIDArray); + DCHECK(!m_pIDArray); m_pIDArray = pdfium::MakeRetain<CPDF_Array>(); - const CPDF_Array* pOldIDArray = m_pParser ? m_pParser->GetIDArray() : nullptr; - const CPDF_Object* pID1 = pOldIDArray ? pOldIDArray->GetObjectAt(0) : nullptr; + RetainPtr<const CPDF_Array> pOldIDArray = + m_pParser ? m_pParser->GetIDArray() : nullptr; + RetainPtr<const CPDF_Object> pID1 = + pOldIDArray ? pOldIDArray->GetObjectAt(0) : nullptr; if (pID1) { - m_pIDArray->Add(pID1->Clone()); + m_pIDArray->Append(pID1->Clone()); } else { ByteString bsBuffer = GenerateFileID((uint32_t)(uintptr_t)this, m_dwLastObjNum); - m_pIDArray->AddNew<CPDF_String>(bsBuffer, true); + m_pIDArray->AppendNew<CPDF_String>(bsBuffer, true); } if (pOldIDArray) { - const CPDF_Object* pID2 = pOldIDArray->GetObjectAt(1); + RetainPtr<const CPDF_Object> pID2 = pOldIDArray->GetObjectAt(1); if (m_IsIncremental && m_pEncryptDict && pID2) { - m_pIDArray->Add(pID2->Clone()); + m_pIDArray->Append(pID2->Clone()); return; } ByteString bsBuffer = GenerateFileID((uint32_t)(uintptr_t)this, m_dwLastObjNum); - m_pIDArray->AddNew<CPDF_String>(bsBuffer, true); + m_pIDArray->AppendNew<CPDF_String>(bsBuffer, true); return; } - m_pIDArray->Add(m_pIDArray->GetObjectAt(0)->Clone()); + m_pIDArray->Append(m_pIDArray->GetObjectAt(0)->Clone()); if (m_pEncryptDict) { - ASSERT(m_pParser); + DCHECK(m_pParser); int revision = m_pEncryptDict->GetIntegerFor("R"); if ((revision == 2 || revision == 3) && - m_pEncryptDict->GetStringFor("Filter") == "Standard") { + m_pEncryptDict->GetByteStringFor("Filter") == "Standard") { m_pNewEncryptDict = ToDictionary(m_pEncryptDict->Clone()); m_pEncryptDict = m_pNewEncryptDict; m_pSecurityHandler = pdfium::MakeRetain<CPDF_SecurityHandler>();
diff --git a/core/fpdfapi/edit/cpdf_creator.h b/core/fpdfapi/edit/cpdf_creator.h index d85d8cf..b97dc29 100644 --- a/core/fpdfapi/edit/cpdf_creator.h +++ b/core/fpdfapi/edit/cpdf_creator.h
@@ -1,4 +1,4 @@ -// Copyright 2014 PDFium Authors. All rights reserved. +// Copyright 2014 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -29,7 +29,7 @@ class CPDF_Creator { public: CPDF_Creator(CPDF_Document* pDoc, - const RetainPtr<IFX_RetainableWriteStream>& archive); + RetainPtr<IFX_RetainableWriteStream> archive); ~CPDF_Creator(); void RemoveSecurity(); @@ -73,11 +73,10 @@ CPDF_CryptoHandler* GetCryptoHandler(); UnownedPtr<CPDF_Document> const m_pDocument; - UnownedPtr<const CPDF_Parser> const m_pParser; + UnownedPtr<CPDF_Parser> const m_pParser; RetainPtr<const CPDF_Dictionary> m_pEncryptDict; RetainPtr<CPDF_Dictionary> m_pNewEncryptDict; RetainPtr<CPDF_SecurityHandler> m_pSecurityHandler; - RetainPtr<const CPDF_Object> m_pMetadata; uint32_t m_dwLastObjNum; std::unique_ptr<IFX_ArchiveStream> m_Archive; FX_FILESIZE m_SavedOffset = 0;
diff --git a/core/fpdfapi/edit/cpdf_creator_embeddertest.cpp b/core/fpdfapi/edit/cpdf_creator_embeddertest.cpp index 9d849c1..8dbad0c 100644 --- a/core/fpdfapi/edit/cpdf_creator_embeddertest.cpp +++ b/core/fpdfapi/edit/cpdf_creator_embeddertest.cpp
@@ -1,13 +1,11 @@ -// Copyright 2017 PDFium Authors. All rights reserved. +// Copyright 2017 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include <cstring> -#include <memory> -#include <string> -#include <vector> +#include <string.h> -#include "core/fxcrt/fx_system.h" +#include <string> + #include "public/cpp/fpdf_scopers.h" #include "public/fpdf_annot.h" #include "public/fpdf_edit.h" @@ -48,7 +46,7 @@ } TEST_F(CPDF_CreatorEmbedderTest, BUG_873) { - EXPECT_TRUE(OpenDocument("embedded_attachments.pdf")); + ASSERT_TRUE(OpenDocument("embedded_attachments.pdf")); EXPECT_TRUE(FPDF_SaveAsCopy(document(), this, 0)); // Cannot match second part of the ID since it is randomly generated. @@ -69,24 +67,24 @@ FileAccessForTesting file_acc("linearized.pdf"); FakeFileAccess fake_acc(&file_acc); - avail_ = FPDFAvail_Create(fake_acc.GetFileAvail(), fake_acc.GetFileAccess()); + CreateAvail(fake_acc.GetFileAvail(), fake_acc.GetFileAccess()); while (PDF_DATA_AVAIL != - FPDFAvail_IsDocAvail(avail_, fake_acc.GetDownloadHints())) { + FPDFAvail_IsDocAvail(avail(), fake_acc.GetDownloadHints())) { fake_acc.SetRequestedDataAvailable(); } - document_ = FPDFAvail_GetDocument(avail_, nullptr); - ASSERT_TRUE(document_); + SetDocumentFromAvail(); + ASSERT_TRUE(document()); // Load second page, to parse additional crossref sections. while (PDF_DATA_AVAIL != - FPDFAvail_IsPageAvail(avail_, 1, fake_acc.GetDownloadHints())) { + FPDFAvail_IsPageAvail(avail(), 1, fake_acc.GetDownloadHints())) { fake_acc.SetRequestedDataAvailable(); } // Simulate downloading of whole file. fake_acc.SetWholeFileAvailable(); // Save document. - EXPECT_TRUE(FPDF_SaveAsCopy(document_, this, 0)); + EXPECT_TRUE(FPDF_SaveAsCopy(document(), this, 0)); const std::string saved_doc = GetString(); EXPECT_THAT(saved_doc, ::testing::HasSubstr("/Info"));
diff --git a/core/fpdfapi/edit/cpdf_pagecontentgenerator.cpp b/core/fpdfapi/edit/cpdf_pagecontentgenerator.cpp index 77d23a2..8717028 100644 --- a/core/fpdfapi/edit/cpdf_pagecontentgenerator.cpp +++ b/core/fpdfapi/edit/cpdf_pagecontentgenerator.cpp
@@ -1,4 +1,4 @@ -// Copyright 2016 PDFium Authors. All rights reserved. +// Copyright 2016 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -9,9 +9,11 @@ #include <map> #include <memory> #include <set> +#include <sstream> #include <tuple> #include <utility> +#include "constants/page_object.h" #include "core/fpdfapi/edit/cpdf_contentstream_write_utils.h" #include "core/fpdfapi/edit/cpdf_pagecontentmanager.h" #include "core/fpdfapi/edit/cpdf_stringarchivestream.h" @@ -19,6 +21,8 @@ #include "core/fpdfapi/font/cpdf_type1font.h" #include "core/fpdfapi/page/cpdf_contentmarks.h" #include "core/fpdfapi/page/cpdf_docpagedata.h" +#include "core/fpdfapi/page/cpdf_form.h" +#include "core/fpdfapi/page/cpdf_formobject.h" #include "core/fpdfapi/page/cpdf_image.h" #include "core/fpdfapi/page/cpdf_imageobject.h" #include "core/fpdfapi/page/cpdf_page.h" @@ -34,11 +38,19 @@ #include "core/fpdfapi/parser/cpdf_stream.h" #include "core/fpdfapi/parser/fpdf_parser_decode.h" #include "core/fpdfapi/parser/fpdf_parser_utility.h" -#include "third_party/base/ptr_util.h" -#include "third_party/base/stl_util.h" +#include "core/fpdfapi/parser/object_tree_traversal_util.h" +#include "third_party/base/check.h" +#include "third_party/base/containers/contains.h" +#include "third_party/base/notreached.h" +#include "third_party/base/numerics/safe_conversions.h" +#include "third_party/base/span.h" namespace { +// Key: The resource type. +// Value: The resource names of a given type. +using ResourcesMap = std::map<ByteString, std::set<ByteString>>; + bool GetColor(const CPDF_Color* pColor, float* rgb) { int intRGB[3]; if (!pColor || !pColor->IsColorSpaceRGB() || @@ -51,6 +63,68 @@ return true; } +void RecordPageObjectResourceUsage(const CPDF_PageObject* page_object, + ResourcesMap& seen_resources) { + const ByteString& resource_name = page_object->GetResourceName(); + if (!resource_name.IsEmpty()) { + switch (page_object->GetType()) { + case CPDF_PageObject::Type::kText: + seen_resources["Font"].insert(resource_name); + break; + case CPDF_PageObject::Type::kImage: + case CPDF_PageObject::Type::kForm: + seen_resources["XObject"].insert(resource_name); + break; + case CPDF_PageObject::Type::kPath: + break; + case CPDF_PageObject::Type::kShading: + break; + } + } + const ByteString& graphics_resource_name = + page_object->GetGraphicsResourceName(); + if (!graphics_resource_name.IsEmpty()) { + seen_resources["ExtGState"].insert(graphics_resource_name); + } +} + +void RemoveUnusedResources(RetainPtr<CPDF_Dictionary> resources_dict, + const ResourcesMap& resources_in_use) { + // TODO(thestig): Remove other unused resource types: + // - ColorSpace + // - Pattern + // - Shading + static constexpr const char* kResourceKeys[] = {"ExtGState", "Font", + "XObject"}; + for (const char* resource_key : kResourceKeys) { + RetainPtr<CPDF_Dictionary> resource_dict = + resources_dict->GetMutableDictFor(resource_key); + if (!resource_dict) { + continue; + } + + std::vector<ByteString> keys; + { + CPDF_DictionaryLocker resource_dict_locker(resource_dict); + for (auto& it : resource_dict_locker) { + keys.push_back(it.first); + } + } + + auto it = resources_in_use.find(resource_key); + const std::set<ByteString>* resource_in_use_of_current_type = + it != resources_in_use.end() ? &it->second : nullptr; + for (const ByteString& key : keys) { + if (resource_in_use_of_current_type && + pdfium::Contains(*resource_in_use_of_current_type, key)) { + continue; + } + + resource_dict->RemoveFor(key.AsStringView()); + } + } +} + } // namespace CPDF_PageContentGenerator::CPDF_PageContentGenerator( @@ -62,22 +136,23 @@ } } -CPDF_PageContentGenerator::~CPDF_PageContentGenerator() {} +CPDF_PageContentGenerator::~CPDF_PageContentGenerator() = default; void CPDF_PageContentGenerator::GenerateContent() { - ASSERT(m_pObjHolder->IsPage()); - - std::map<int32_t, std::unique_ptr<std::ostringstream>> stream = + DCHECK(m_pObjHolder->IsPage()); + std::map<int32_t, fxcrt::ostringstream> new_stream_data = GenerateModifiedStreams(); + // If no streams were regenerated or removed, nothing to do here. + if (new_stream_data.empty()) { + return; + } - UpdateContentStreams(&stream); + UpdateContentStreams(std::move(new_stream_data)); + UpdateResourcesDict(); } -std::map<int32_t, std::unique_ptr<std::ostringstream>> +std::map<int32_t, fxcrt::ostringstream> CPDF_PageContentGenerator::GenerateModifiedStreams() { - // Make sure default graphics are created. - GetOrCreateDefaultGraphics(); - // Figure out which streams are dirty. std::set<int32_t> all_dirty_streams; for (auto& pPageObj : m_pageObjects) { @@ -89,23 +164,21 @@ marked_dirty_streams.end()); // Start regenerating dirty streams. - std::map<int32_t, std::unique_ptr<std::ostringstream>> streams; + std::map<int32_t, fxcrt::ostringstream> streams; std::set<int32_t> empty_streams; std::unique_ptr<const CPDF_ContentMarks> empty_content_marks = - pdfium::MakeUnique<CPDF_ContentMarks>(); + std::make_unique<CPDF_ContentMarks>(); std::map<int32_t, const CPDF_ContentMarks*> current_content_marks; for (int32_t dirty_stream : all_dirty_streams) { - std::unique_ptr<std::ostringstream> buf = - pdfium::MakeUnique<std::ostringstream>(); + fxcrt::ostringstream buf; // Set the default graphic state values - *buf << "q\n"; + buf << "q\n"; if (!m_pObjHolder->GetLastCTM().IsIdentity()) - *buf << m_pObjHolder->GetLastCTM().GetInverse() << " cm\n"; + WriteMatrix(buf, m_pObjHolder->GetLastCTM().GetInverse()) << " cm\n"; - ProcessDefaultGraphics(buf.get()); - + ProcessDefaultGraphics(&buf); streams[dirty_stream] = std::move(buf); empty_streams.insert(dirty_stream); current_content_marks[dirty_stream] = empty_content_marks.get(); @@ -118,17 +191,17 @@ if (it == streams.end()) continue; - std::ostringstream* buf = it->second.get(); + fxcrt::ostringstream* buf = &it->second; empty_streams.erase(stream_index); - current_content_marks[stream_index] = ProcessContentMarks( - buf, pPageObj.Get(), current_content_marks[stream_index]); - ProcessPageObject(buf, pPageObj.Get()); + current_content_marks[stream_index] = + ProcessContentMarks(buf, pPageObj, current_content_marks[stream_index]); + ProcessPageObject(buf, pPageObj); } // Finish dirty streams. for (int32_t dirty_stream : all_dirty_streams) { - std::ostringstream* buf = streams[dirty_stream].get(); - if (pdfium::ContainsKey(empty_streams, dirty_stream)) { + fxcrt::ostringstream* buf = &streams[dirty_stream]; + if (pdfium::Contains(empty_streams, dirty_stream)) { // Clear to show that this stream needs to be deleted. buf->str(""); } else { @@ -143,70 +216,91 @@ } void CPDF_PageContentGenerator::UpdateContentStreams( - std::map<int32_t, std::unique_ptr<std::ostringstream>>* new_stream_data) { - // If no streams were regenerated or removed, nothing to do here. - if (new_stream_data->empty()) - return; + std::map<int32_t, fxcrt::ostringstream>&& new_stream_data) { + CHECK(!new_stream_data.empty()); - CPDF_PageContentManager page_content_manager(m_pObjHolder.Get()); + // Make sure default graphics are created. + m_DefaultGraphicsName = GetOrCreateDefaultGraphics(); - for (auto& pair : *new_stream_data) { + CPDF_PageContentManager page_content_manager(m_pObjHolder, m_pDocument); + for (auto& pair : new_stream_data) { int32_t stream_index = pair.first; - std::ostringstream* buf = pair.second.get(); + fxcrt::ostringstream* buf = &pair.second; if (stream_index == CPDF_PageObject::kNoContentStream) { - int new_stream_index = page_content_manager.AddStream(buf); + int new_stream_index = + pdfium::base::checked_cast<int>(page_content_manager.AddStream(buf)); UpdateStreamlessPageObjects(new_stream_index); continue; } - CPDF_Stream* old_stream = - page_content_manager.GetStreamByIndex(stream_index); - ASSERT(old_stream); + page_content_manager.UpdateStream(stream_index, buf); + } +} - // If buf is now empty, remove the stream instead of setting the data. - if (buf->tellp() <= 0) - page_content_manager.ScheduleRemoveStreamByIndex(stream_index); - else - old_stream->SetDataFromStringstreamAndRemoveFilter(buf); +void CPDF_PageContentGenerator::UpdateResourcesDict() { + RetainPtr<CPDF_Dictionary> resources = m_pObjHolder->GetMutableResources(); + if (!resources) { + return; } - page_content_manager.ExecuteScheduledRemovals(); + const uint32_t resources_object_number = resources->GetObjNum(); + if (resources_object_number) { + // If `resources` is not an inline object, then do not modify it directly if + // it has multiple references. + if (pdfium::Contains(GetObjectsWithMultipleReferences(m_pDocument), + resources_object_number)) { + resources = pdfium::WrapRetain(resources->Clone()->AsMutableDictionary()); + const uint32_t clone_object_number = + m_pDocument->AddIndirectObject(resources); + m_pObjHolder->SetResources(resources); + m_pObjHolder->GetMutableDict()->SetNewFor<CPDF_Reference>( + pdfium::page_object::kResources, m_pDocument, clone_object_number); + } + } + + ResourcesMap seen_resources; + for (auto& page_object : m_pageObjects) { + RecordPageObjectResourceUsage(page_object, seen_resources); + } + if (!m_DefaultGraphicsName.IsEmpty()) { + seen_resources["ExtGState"].insert(m_DefaultGraphicsName); + } + + RemoveUnusedResources(std::move(resources), seen_resources); } ByteString CPDF_PageContentGenerator::RealizeResource( const CPDF_Object* pResource, const ByteString& bsType) const { - ASSERT(pResource); - if (!m_pObjHolder->m_pResources) { - m_pObjHolder->m_pResources.Reset( - m_pDocument->NewIndirect<CPDF_Dictionary>()); - m_pObjHolder->GetDict()->SetNewFor<CPDF_Reference>( - "Resources", m_pDocument.Get(), - m_pObjHolder->m_pResources->GetObjNum()); + DCHECK(pResource); + if (!m_pObjHolder->GetResources()) { + m_pObjHolder->SetResources(m_pDocument->NewIndirect<CPDF_Dictionary>()); + m_pObjHolder->GetMutableDict()->SetNewFor<CPDF_Reference>( + pdfium::page_object::kResources, m_pDocument, + m_pObjHolder->GetResources()->GetObjNum()); } - CPDF_Dictionary* pResList = m_pObjHolder->m_pResources->GetDictFor(bsType); - if (!pResList) - pResList = m_pObjHolder->m_pResources->SetNewFor<CPDF_Dictionary>(bsType); + RetainPtr<CPDF_Dictionary> pResList = + m_pObjHolder->GetMutableResources()->GetOrCreateDictFor(bsType); ByteString name; int idnum = 1; - while (1) { + while (true) { name = ByteString::Format("FX%c%d", bsType[0], idnum); if (!pResList->KeyExist(name)) break; idnum++; } - pResList->SetNewFor<CPDF_Reference>(name, m_pDocument.Get(), + pResList->SetNewFor<CPDF_Reference>(name, m_pDocument, pResource->GetObjNum()); return name; } -bool CPDF_PageContentGenerator::ProcessPageObjects(std::ostringstream* buf) { +bool CPDF_PageContentGenerator::ProcessPageObjects(fxcrt::ostringstream* buf) { bool bDirty = false; std::unique_ptr<const CPDF_ContentMarks> empty_content_marks = - pdfium::MakeUnique<CPDF_ContentMarks>(); + std::make_unique<CPDF_ContentMarks>(); const CPDF_ContentMarks* content_marks = empty_content_marks.get(); for (auto& pPageObj : m_pageObjects) { @@ -214,8 +308,8 @@ continue; bDirty = true; - content_marks = ProcessContentMarks(buf, pPageObj.Get(), content_marks); - ProcessPageObject(buf, pPageObj.Get()); + content_marks = ProcessContentMarks(buf, pPageObj, content_marks); + ProcessPageObject(buf, pPageObj); } FinishMarks(buf, content_marks); return bDirty; @@ -230,12 +324,11 @@ } const CPDF_ContentMarks* CPDF_PageContentGenerator::ProcessContentMarks( - std::ostringstream* buf, + fxcrt::ostringstream* buf, const CPDF_PageObject* pPageObj, const CPDF_ContentMarks* pPrev) { - const CPDF_ContentMarks* pNext = &pPageObj->m_ContentMarks; - - size_t first_different = pPrev->FindFirstDifference(pNext); + const CPDF_ContentMarks* pNext = pPageObj->GetContentMarks(); + const size_t first_different = pPrev->FindFirstDifference(pNext); // Close all marks that are in prev but not in next. // Technically we should iterate backwards to close from the top to the @@ -282,7 +375,7 @@ } void CPDF_PageContentGenerator::FinishMarks( - std::ostringstream* buf, + fxcrt::ostringstream* buf, const CPDF_ContentMarks* pContentMarks) { // Technically we should iterate backwards to close from the top to the // bottom, but since the EMC operators do not identify which mark they are @@ -291,10 +384,12 @@ *buf << "EMC\n"; } -void CPDF_PageContentGenerator::ProcessPageObject(std::ostringstream* buf, +void CPDF_PageContentGenerator::ProcessPageObject(fxcrt::ostringstream* buf, CPDF_PageObject* pPageObj) { if (CPDF_ImageObject* pImageObject = pPageObj->AsImage()) ProcessImage(buf, pImageObject); + else if (CPDF_FormObject* pFormObj = pPageObj->AsForm()) + ProcessForm(buf, pFormObj); else if (CPDF_PathObject* pPathObj = pPageObj->AsPath()) ProcessPath(buf, pPathObj); else if (CPDF_TextObject* pTextObj = pPageObj->AsText()) @@ -302,36 +397,59 @@ pPageObj->SetDirty(false); } -void CPDF_PageContentGenerator::ProcessImage(std::ostringstream* buf, +void CPDF_PageContentGenerator::ProcessImage(fxcrt::ostringstream* buf, CPDF_ImageObject* pImageObj) { if ((pImageObj->matrix().a == 0 && pImageObj->matrix().b == 0) || (pImageObj->matrix().c == 0 && pImageObj->matrix().d == 0)) { return; } - *buf << "q " << pImageObj->matrix() << " cm "; RetainPtr<CPDF_Image> pImage = pImageObj->GetImage(); if (pImage->IsInline()) return; - CPDF_Stream* pStream = pImage->GetStream(); + RetainPtr<const CPDF_Stream> pStream = pImage->GetStream(); if (!pStream) return; + *buf << "q "; + WriteMatrix(*buf, pImageObj->matrix()) << " cm "; + bool bWasInline = pStream->IsInline(); if (bWasInline) pImage->ConvertStreamToIndirectObject(); ByteString name = RealizeResource(pStream, "XObject"); + pImageObj->SetResourceName(name); + if (bWasInline) { - auto* pPageData = CPDF_DocPageData::FromDocument(m_pDocument.Get()); + auto* pPageData = CPDF_DocPageData::FromDocument(m_pDocument); pImageObj->SetImage(pPageData->GetImage(pStream->GetObjNum())); } *buf << "/" << PDF_NameEncode(name) << " Do Q\n"; } -// Processing path with operators from Tables 4.9 and 4.10 of PDF spec 1.7: +void CPDF_PageContentGenerator::ProcessForm(fxcrt::ostringstream* buf, + CPDF_FormObject* pFormObj) { + if ((pFormObj->form_matrix().a == 0 && pFormObj->form_matrix().b == 0) || + (pFormObj->form_matrix().c == 0 && pFormObj->form_matrix().d == 0)) { + return; + } + + RetainPtr<const CPDF_Stream> pStream = pFormObj->form()->GetStream(); + if (!pStream) + return; + + ByteString name = RealizeResource(pStream.Get(), "XObject"); + pFormObj->SetResourceName(name); + + *buf << "q\n"; + WriteMatrix(*buf, pFormObj->form_matrix()) << " cm "; + *buf << "/" << PDF_NameEncode(name) << " Do Q\n"; +} + +// Processing path construction with operators from Table 4.9 of PDF spec 1.7: // "re" appends a rectangle (here, used only if the whole path is a rectangle) // "m" moves current point to the given coordinates // "l" creates a line from current point to the new point @@ -339,49 +457,56 @@ // points as the Bezier control points // Note: "l", "c" change the current point // "h" closes the subpath (appends a line from current to starting point) +void CPDF_PageContentGenerator::ProcessPathPoints(fxcrt::ostringstream* buf, + CPDF_Path* pPath) { + pdfium::span<const CFX_Path::Point> points = pPath->GetPoints(); + if (pPath->IsRect()) { + CFX_PointF diff = points[2].m_Point - points[0].m_Point; + WritePoint(*buf, points[0].m_Point) << " "; + WritePoint(*buf, diff) << " re"; + return; + } + for (size_t i = 0; i < points.size(); ++i) { + if (i > 0) + *buf << " "; + + WritePoint(*buf, points[i].m_Point); + + CFX_Path::Point::Type point_type = points[i].m_Type; + if (point_type == CFX_Path::Point::Type::kMove) { + *buf << " m"; + } else if (point_type == CFX_Path::Point::Type::kLine) { + *buf << " l"; + } else if (point_type == CFX_Path::Point::Type::kBezier) { + if (i + 2 >= points.size() || + !points[i].IsTypeAndOpen(CFX_Path::Point::Type::kBezier) || + !points[i + 1].IsTypeAndOpen(CFX_Path::Point::Type::kBezier) || + points[i + 2].m_Type != CFX_Path::Point::Type::kBezier) { + // If format is not supported, close the path and paint + *buf << " h"; + break; + } + *buf << " "; + WritePoint(*buf, points[i + 1].m_Point) << " "; + WritePoint(*buf, points[i + 2].m_Point) << " c"; + i += 2; + } + if (points[i].m_CloseFigure) + *buf << " h"; + } +} + +// Processing path painting with operators from Table 4.10 of PDF spec 1.7: // Path painting operators: "S", "n", "B", "f", "B*", "f*", depending on // the filling mode and whether we want stroking the path or not. // "Q" restores the graphics state imposed by the ProcessGraphics method. -void CPDF_PageContentGenerator::ProcessPath(std::ostringstream* buf, +void CPDF_PageContentGenerator::ProcessPath(fxcrt::ostringstream* buf, CPDF_PathObject* pPathObj) { ProcessGraphics(buf, pPathObj); - *buf << pPathObj->matrix() << " cm "; + WriteMatrix(*buf, pPathObj->matrix()) << " cm "; + ProcessPathPoints(buf, &pPathObj->path()); - const auto& pPoints = pPathObj->path().GetPoints(); - if (pPathObj->path().IsRect()) { - CFX_PointF diff = pPoints[2].m_Point - pPoints[0].m_Point; - *buf << pPoints[0].m_Point << " " << diff << " re"; - } else { - for (size_t i = 0; i < pPoints.size(); i++) { - if (i > 0) - *buf << " "; - - *buf << pPoints[i].m_Point; - - FXPT_TYPE pointType = pPoints[i].m_Type; - if (pointType == FXPT_TYPE::MoveTo) { - *buf << " m"; - } else if (pointType == FXPT_TYPE::LineTo) { - *buf << " l"; - } else if (pointType == FXPT_TYPE::BezierTo) { - if (i + 2 >= pPoints.size() || - !pPoints[i].IsTypeAndOpen(FXPT_TYPE::BezierTo) || - !pPoints[i + 1].IsTypeAndOpen(FXPT_TYPE::BezierTo) || - pPoints[i + 2].m_Type != FXPT_TYPE::BezierTo) { - // If format is not supported, close the path and paint - *buf << " h"; - break; - } - *buf << " "; - *buf << pPoints[i + 1].m_Point << " "; - *buf << pPoints[i + 2].m_Point << " c"; - i += 2; - } - if (pPoints[i].m_CloseFigure) - *buf << " h"; - } - } if (pPathObj->has_no_filltype()) *buf << (pPathObj->stroke() ? " S" : " n"); else if (pPathObj->has_winding_filltype()) @@ -398,8 +523,10 @@ // "rg" sets the fill color, "RG" sets the stroke color (using DefaultRGB) // "w" sets the stroke line width. // "ca" sets the fill alpha, "CA" sets the stroke alpha. +// "W" and "W*" modify the clipping path using the nonzero winding rule and +// even-odd rules, respectively. // "q" saves the graphics state, so that the settings can later be reversed -void CPDF_PageContentGenerator::ProcessGraphics(std::ostringstream* buf, +void CPDF_PageContentGenerator::ProcessGraphics(fxcrt::ostringstream* buf, CPDF_PageObject* pPageObj) { *buf << "q "; float fillColor[3]; @@ -416,12 +543,35 @@ if (lineWidth != 1.0f) WriteFloat(*buf, lineWidth) << " w "; CFX_GraphStateData::LineCap lineCap = pPageObj->m_GraphState.GetLineCap(); - if (lineCap != CFX_GraphStateData::LineCapButt) + if (lineCap != CFX_GraphStateData::LineCap::kButt) *buf << static_cast<int>(lineCap) << " J "; CFX_GraphStateData::LineJoin lineJoin = pPageObj->m_GraphState.GetLineJoin(); - if (lineJoin != CFX_GraphStateData::LineJoinMiter) + if (lineJoin != CFX_GraphStateData::LineJoin::kMiter) *buf << static_cast<int>(lineJoin) << " j "; + const CPDF_ClipPath& clip_path = pPageObj->m_ClipPath; + if (clip_path.HasRef()) { + for (size_t i = 0; i < clip_path.GetPathCount(); ++i) { + CPDF_Path path = clip_path.GetPath(i); + ProcessPathPoints(buf, &path); + switch (clip_path.GetClipType(i)) { + case CFX_FillRenderOptions::FillType::kWinding: + *buf << " W "; + break; + case CFX_FillRenderOptions::FillType::kEvenOdd: + *buf << " W* "; + break; + case CFX_FillRenderOptions::FillType::kNoFill: + NOTREACHED(); + break; + } + + // Use a no-op path-painting operator to terminate the path without + // causing any marks to be placed on the page. + *buf << "n "; + } + } + GraphicsData graphD; graphD.fillAlpha = pPageObj->m_GeneralState.GetFillAlpha(); graphD.strokeAlpha = pPageObj->m_GeneralState.GetStrokeAlpha(); @@ -432,9 +582,10 @@ } ByteString name; - auto it = m_pObjHolder->m_GraphicsMap.find(graphD); - if (it != m_pObjHolder->m_GraphicsMap.end()) { - name = it->second; + absl::optional<ByteString> maybe_name = + m_pObjHolder->GraphicsMapSearch(graphD); + if (maybe_name.has_value()) { + name = std::move(maybe_name.value()); } else { auto gsDict = pdfium::MakeRetain<CPDF_Dictionary>(); if (graphD.fillAlpha != 1.0f) @@ -447,20 +598,21 @@ gsDict->SetNewFor<CPDF_Name>("BM", pPageObj->m_GeneralState.GetBlendMode()); } - CPDF_Object* pDict = m_pDocument->AddIndirectObject(gsDict); - name = RealizeResource(pDict, "ExtGState"); - m_pObjHolder->m_GraphicsMap[graphD] = name; + m_pDocument->AddIndirectObject(gsDict); + name = RealizeResource(std::move(gsDict), "ExtGState"); + pPageObj->SetGraphicsResourceName(name); + m_pObjHolder->GraphicsMapInsert(graphD, name); } *buf << "/" << PDF_NameEncode(name) << " gs "; } void CPDF_PageContentGenerator::ProcessDefaultGraphics( - std::ostringstream* buf) { + fxcrt::ostringstream* buf) { *buf << "0 0 0 RG 0 0 0 rg 1 w " - << static_cast<int>(CFX_GraphStateData::LineCapButt) << " J " - << static_cast<int>(CFX_GraphStateData::LineJoinMiter) << " j\n"; - ByteString name = GetOrCreateDefaultGraphics(); - *buf << "/" << PDF_NameEncode(name) << " gs "; + << static_cast<int>(CFX_GraphStateData::LineCap::kButt) << " J " + << static_cast<int>(CFX_GraphStateData::LineJoin::kMiter) << " j\n"; + m_DefaultGraphicsName = GetOrCreateDefaultGraphics(); + *buf << "/" << PDF_NameEncode(m_DefaultGraphicsName) << " gs "; } ByteString CPDF_PageContentGenerator::GetOrCreateDefaultGraphics() const { @@ -468,34 +620,35 @@ defaultGraphics.fillAlpha = 1.0f; defaultGraphics.strokeAlpha = 1.0f; defaultGraphics.blendType = BlendMode::kNormal; - auto it = m_pObjHolder->m_GraphicsMap.find(defaultGraphics); - // If default graphics already exists, return it. - if (it != m_pObjHolder->m_GraphicsMap.end()) - return it->second; + absl::optional<ByteString> maybe_name = + m_pObjHolder->GraphicsMapSearch(defaultGraphics); + if (maybe_name.has_value()) + return maybe_name.value(); - // Otherwise, create them. auto gsDict = pdfium::MakeRetain<CPDF_Dictionary>(); gsDict->SetNewFor<CPDF_Number>("ca", defaultGraphics.fillAlpha); gsDict->SetNewFor<CPDF_Number>("CA", defaultGraphics.strokeAlpha); gsDict->SetNewFor<CPDF_Name>("BM", "Normal"); - CPDF_Object* pDict = m_pDocument->AddIndirectObject(gsDict); - ByteString name = RealizeResource(pDict, "ExtGState"); - m_pObjHolder->m_GraphicsMap[defaultGraphics] = name; + m_pDocument->AddIndirectObject(gsDict); + ByteString name = RealizeResource(std::move(gsDict), "ExtGState"); + m_pObjHolder->GraphicsMapInsert(defaultGraphics, name); return name; } // This method adds text to the buffer, BT begins the text object, ET ends it. // Tm sets the text matrix (allows positioning and transforming text). // Tf sets the font name (from Font in Resources) and font size. +// Tr sets the text rendering mode. // Tj sets the actual text, <####...> is used when specifying charcodes. -void CPDF_PageContentGenerator::ProcessText(std::ostringstream* buf, +void CPDF_PageContentGenerator::ProcessText(fxcrt::ostringstream* buf, CPDF_TextObject* pTextObj) { ProcessGraphics(buf, pTextObj); - *buf << "BT " << pTextObj->GetTextMatrix() << " Tm "; + *buf << "BT "; + WriteMatrix(*buf, pTextObj->GetTextMatrix()) << " Tm "; RetainPtr<CPDF_Font> pFont(pTextObj->GetFont()); if (!pFont) - pFont = CPDF_Font::GetStockFont(m_pDocument.Get(), "Helvetica"); + pFont = CPDF_Font::GetStockFont(m_pDocument, "Helvetica"); FontData data; const CPDF_FontEncoding* pEncoding = nullptr; @@ -511,12 +664,13 @@ return; } data.baseFont = pFont->GetBaseFontName(); - auto it = m_pObjHolder->m_FontsMap.find(data); - ByteString dictName; - if (it != m_pObjHolder->m_FontsMap.end()) { - dictName = it->second; + + ByteString dict_name; + absl::optional<ByteString> maybe_name = m_pObjHolder->FontsMapSearch(data); + if (maybe_name.has_value()) { + dict_name = std::move(maybe_name.value()); } else { - CPDF_Object* pIndirectFont = pFont->GetFontDict(); + RetainPtr<const CPDF_Object> pIndirectFont = pFont->GetFontDict(); if (pIndirectFont->IsInline()) { // In this case we assume it must be a standard font auto pFontDict = pdfium::MakeRetain<CPDF_Dictionary>(); @@ -527,18 +681,22 @@ pFontDict->SetFor("Encoding", pEncoding->Realize(m_pDocument->GetByteStringPool())); } - pIndirectFont = m_pDocument->AddIndirectObject(pFontDict); + m_pDocument->AddIndirectObject(pFontDict); + pIndirectFont = std::move(pFontDict); } - dictName = RealizeResource(pIndirectFont, "Font"); - m_pObjHolder->m_FontsMap[data] = dictName; + dict_name = RealizeResource(std::move(pIndirectFont), "Font"); + m_pObjHolder->FontsMapInsert(data, dict_name); } - *buf << "/" << PDF_NameEncode(dictName) << " "; + pTextObj->SetResourceName(dict_name); + + *buf << "/" << PDF_NameEncode(dict_name) << " "; WriteFloat(*buf, pTextObj->GetFontSize()) << " Tf "; + *buf << static_cast<int>(pTextObj->GetTextRenderMode()) << " Tr "; ByteString text; for (uint32_t charcode : pTextObj->GetCharCodes()) { if (charcode != CPDF_Font::kInvalidCharCode) pFont->AppendChar(&text, charcode); } - *buf << PDF_EncodeString(text, true) << " Tj ET"; + *buf << PDF_HexEncodeString(text.AsStringView()) << " Tj ET"; *buf << " Q\n"; }
diff --git a/core/fpdfapi/edit/cpdf_pagecontentgenerator.h b/core/fpdfapi/edit/cpdf_pagecontentgenerator.h index 40d19ae..06bb239 100644 --- a/core/fpdfapi/edit/cpdf_pagecontentgenerator.h +++ b/core/fpdfapi/edit/cpdf_pagecontentgenerator.h
@@ -1,4 +1,4 @@ -// Copyright 2016 PDFium Authors. All rights reserved. +// Copyright 2016 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -7,21 +7,23 @@ #ifndef CORE_FPDFAPI_EDIT_CPDF_PAGECONTENTGENERATOR_H_ #define CORE_FPDFAPI_EDIT_CPDF_PAGECONTENTGENERATOR_H_ +#include <stdint.h> + #include <map> -#include <memory> -#include <sstream> #include <vector> -#include "core/fxcrt/fx_string.h" -#include "core/fxcrt/fx_system.h" +#include "core/fxcrt/bytestring.h" +#include "core/fxcrt/fx_string_wrappers.h" #include "core/fxcrt/unowned_ptr.h" class CPDF_ContentMarks; class CPDF_Document; +class CPDF_FormObject; class CPDF_ImageObject; class CPDF_Object; class CPDF_PageObject; class CPDF_PageObjectHolder; +class CPDF_Path; class CPDF_PathObject; class CPDF_TextObject; @@ -31,43 +33,50 @@ ~CPDF_PageContentGenerator(); void GenerateContent(); - bool ProcessPageObjects(std::ostringstream* buf); + bool ProcessPageObjects(fxcrt::ostringstream* buf); private: friend class CPDF_PageContentGeneratorTest; - void ProcessPageObject(std::ostringstream* buf, CPDF_PageObject* pPageObj); - void ProcessPath(std::ostringstream* buf, CPDF_PathObject* pPathObj); - void ProcessImage(std::ostringstream* buf, CPDF_ImageObject* pImageObj); - void ProcessGraphics(std::ostringstream* buf, CPDF_PageObject* pPageObj); - void ProcessDefaultGraphics(std::ostringstream* buf); - void ProcessText(std::ostringstream* buf, CPDF_TextObject* pTextObj); + void ProcessPageObject(fxcrt::ostringstream* buf, CPDF_PageObject* pPageObj); + void ProcessPathPoints(fxcrt::ostringstream* buf, CPDF_Path* pPath); + void ProcessPath(fxcrt::ostringstream* buf, CPDF_PathObject* pPathObj); + void ProcessForm(fxcrt::ostringstream* buf, CPDF_FormObject* pFormObj); + void ProcessImage(fxcrt::ostringstream* buf, CPDF_ImageObject* pImageObj); + void ProcessGraphics(fxcrt::ostringstream* buf, CPDF_PageObject* pPageObj); + void ProcessDefaultGraphics(fxcrt::ostringstream* buf); + void ProcessText(fxcrt::ostringstream* buf, CPDF_TextObject* pTextObj); ByteString GetOrCreateDefaultGraphics() const; ByteString RealizeResource(const CPDF_Object* pResource, const ByteString& bsType) const; - const CPDF_ContentMarks* ProcessContentMarks(std::ostringstream* buf, + const CPDF_ContentMarks* ProcessContentMarks(fxcrt::ostringstream* buf, const CPDF_PageObject* pPageObj, const CPDF_ContentMarks* pPrev); - void FinishMarks(std::ostringstream* buf, + void FinishMarks(fxcrt::ostringstream* buf, const CPDF_ContentMarks* pContentMarks); // Returns a map from content stream index to new stream data. Unmodified // streams are not touched. - std::map<int32_t, std::unique_ptr<std::ostringstream>> - GenerateModifiedStreams(); + std::map<int32_t, fxcrt::ostringstream> GenerateModifiedStreams(); - // Add buffer as a stream in page's 'Contents' + // For each entry in `new_stream_data`, adds the string buffer to the page's + // content stream. void UpdateContentStreams( - std::map<int32_t, std::unique_ptr<std::ostringstream>>* new_stream_data); + std::map<int32_t, fxcrt::ostringstream>&& new_stream_data); - // Set the stream index of all page objects with stream index == + // Sets the stream index of all page objects with stream index == // |CPDF_PageObject::kNoContentStream|. These are new objects that had not // been parsed from or written to any content stream yet. void UpdateStreamlessPageObjects(int new_content_stream_index); + // Updates the resource dictionary for `m_pObjHolder` to account for all the + // changes. + void UpdateResourcesDict(); + UnownedPtr<CPDF_PageObjectHolder> const m_pObjHolder; UnownedPtr<CPDF_Document> const m_pDocument; std::vector<UnownedPtr<CPDF_PageObject>> m_pageObjects; + ByteString m_DefaultGraphicsName; }; #endif // CORE_FPDFAPI_EDIT_CPDF_PAGECONTENTGENERATOR_H_
diff --git a/core/fpdfapi/edit/cpdf_pagecontentgenerator_unittest.cpp b/core/fpdfapi/edit/cpdf_pagecontentgenerator_unittest.cpp index 62c3df5..8d6aa1f 100644 --- a/core/fpdfapi/edit/cpdf_pagecontentgenerator_unittest.cpp +++ b/core/fpdfapi/edit/cpdf_pagecontentgenerator_unittest.cpp
@@ -1,9 +1,10 @@ -// Copyright 2017 PDFium Authors. All rights reserved. +// Copyright 2017 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "core/fpdfapi/edit/cpdf_pagecontentgenerator.h" +#include <iterator> #include <memory> #include <utility> @@ -12,65 +13,66 @@ #include "core/fpdfapi/page/cpdf_docpagedata.h" #include "core/fpdfapi/page/cpdf_form.h" #include "core/fpdfapi/page/cpdf_page.h" -#include "core/fpdfapi/page/cpdf_pagemodule.h" #include "core/fpdfapi/page/cpdf_pathobject.h" #include "core/fpdfapi/page/cpdf_textobject.h" +#include "core/fpdfapi/page/cpdf_textstate.h" +#include "core/fpdfapi/page/test_with_page_module.h" #include "core/fpdfapi/parser/cpdf_dictionary.h" #include "core/fpdfapi/parser/cpdf_document.h" #include "core/fpdfapi/parser/cpdf_name.h" #include "core/fpdfapi/parser/cpdf_parser.h" #include "core/fpdfapi/parser/cpdf_reference.h" #include "core/fpdfapi/parser/cpdf_stream.h" -#include "core/fpdfapi/render/cpdf_docrenderdata.h" -#include "core/fxcrt/fx_memory_wrappers.h" -#include "core/fxge/render_defines.h" +#include "core/fpdfapi/parser/cpdf_test_document.h" +#include "core/fxcrt/data_vector.h" +#include "core/fxge/cfx_fillrenderoptions.h" #include "testing/gtest/include/gtest/gtest.h" -#include "third_party/base/ptr_util.h" -class CPDF_PageContentGeneratorTest : public testing::Test { +class CPDF_PageContentGeneratorTest : public TestWithPageModule { protected: - void SetUp() override { CPDF_PageModule::Create(); } - void TearDown() override { CPDF_PageModule::Destroy(); } - void TestProcessPath(CPDF_PageContentGenerator* pGen, - std::ostringstream* buf, + fxcrt::ostringstream* buf, CPDF_PathObject* pPathObj) { pGen->ProcessPath(buf, pPathObj); } - CPDF_Dictionary* TestGetResource(CPDF_PageContentGenerator* pGen, - const ByteString& type, - const ByteString& name) { - return pGen->m_pObjHolder->m_pResources->GetDictFor(type)->GetDictFor(name); + RetainPtr<const CPDF_Dictionary> TestGetResource( + CPDF_PageContentGenerator* pGen, + const ByteString& type, + const ByteString& name) { + RetainPtr<const CPDF_Dictionary> pResources = + pGen->m_pObjHolder->GetResources(); + return pResources->GetDictFor(type)->GetDictFor(name); } void TestProcessText(CPDF_PageContentGenerator* pGen, - std::ostringstream* buf, + fxcrt::ostringstream* buf, CPDF_TextObject* pTextObj) { pGen->ProcessText(buf, pTextObj); } }; TEST_F(CPDF_PageContentGeneratorTest, ProcessRect) { - auto pPathObj = pdfium::MakeUnique<CPDF_PathObject>(); + auto pPathObj = std::make_unique<CPDF_PathObject>(); pPathObj->set_stroke(true); - pPathObj->set_filltype(FXFILL_ALTERNATE); + pPathObj->set_filltype(CFX_FillRenderOptions::FillType::kEvenOdd); pPathObj->path().AppendRect(10, 5, 13, 30); auto dummy_page_dict = pdfium::MakeRetain<CPDF_Dictionary>(); - auto pTestPage = - pdfium::MakeRetain<CPDF_Page>(nullptr, dummy_page_dict.Get()); + auto pTestPage = pdfium::MakeRetain<CPDF_Page>(nullptr, dummy_page_dict); CPDF_PageContentGenerator generator(pTestPage.Get()); - std::ostringstream buf; + fxcrt::ostringstream buf; TestProcessPath(&generator, &buf, pPathObj.get()); EXPECT_EQ("q 1 0 0 1 0 0 cm 10 5 3 25 re B* Q\n", ByteString(buf)); - pPathObj = pdfium::MakeUnique<CPDF_PathObject>(); - pPathObj->path().AppendPoint(CFX_PointF(0, 0), FXPT_TYPE::MoveTo, false); - pPathObj->path().AppendPoint(CFX_PointF(5.2f, 0), FXPT_TYPE::LineTo, false); - pPathObj->path().AppendPoint(CFX_PointF(5.2f, 3.78f), FXPT_TYPE::LineTo, - false); - pPathObj->path().AppendPoint(CFX_PointF(0, 3.78f), FXPT_TYPE::LineTo, true); + pPathObj = std::make_unique<CPDF_PathObject>(); + pPathObj->path().AppendPoint(CFX_PointF(0, 0), CFX_Path::Point::Type::kMove); + pPathObj->path().AppendPoint(CFX_PointF(5.2f, 0), + CFX_Path::Point::Type::kLine); + pPathObj->path().AppendPoint(CFX_PointF(5.2f, 3.78f), + CFX_Path::Point::Type::kLine); + pPathObj->path().AppendPointAndClose(CFX_PointF(0, 3.78f), + CFX_Path::Point::Type::kLine); buf.str(""); TestProcessPath(&generator, &buf, pPathObj.get()); EXPECT_EQ("q 1 0 0 1 0 0 cm 0 0 5.1999998 3.78 re n Q\n", ByteString(buf)); @@ -78,10 +80,11 @@ TEST_F(CPDF_PageContentGeneratorTest, BUG_937) { static const std::vector<float> rgb = {0.000000000000000000001f, 0.7f, 0.35f}; - RetainPtr<CPDF_ColorSpace> pCS = CPDF_ColorSpace::GetStockCS(PDFCS_DEVICERGB); + RetainPtr<CPDF_ColorSpace> pCS = + CPDF_ColorSpace::GetStockCS(CPDF_ColorSpace::Family::kDeviceRGB); { - auto pPathObj = pdfium::MakeUnique<CPDF_PathObject>(); - pPathObj->set_filltype(FXFILL_WINDING); + auto pPathObj = std::make_unique<CPDF_PathObject>(); + pPathObj->set_filltype(CFX_FillRenderOptions::FillType::kWinding); // Test code in ProcessPath that generates re operator pPathObj->path().AppendRect(0.000000000000000000001, @@ -94,10 +97,9 @@ 200000000000000.000002)); auto dummy_page_dict = pdfium::MakeRetain<CPDF_Dictionary>(); - auto pTestPage = - pdfium::MakeRetain<CPDF_Page>(nullptr, dummy_page_dict.Get()); + auto pTestPage = pdfium::MakeRetain<CPDF_Page>(nullptr, dummy_page_dict); CPDF_PageContentGenerator generator(pTestPage.Get()); - std::ostringstream buf; + fxcrt::ostringstream buf; TestProcessPath(&generator, &buf, pPathObj.get()); EXPECT_EQ( "q 0 0.701961 0.34902 rg 0 0.701961 0.34902 RG 200000000000000000000 w" @@ -108,30 +110,29 @@ { // Test code in ProcessPath that handles bezier operator - auto pPathObj = pdfium::MakeUnique<CPDF_PathObject>(); + auto pPathObj = std::make_unique<CPDF_PathObject>(); pPathObj->m_ColorState.SetFillColor(pCS, rgb); pPathObj->m_ColorState.SetStrokeColor(pCS, rgb); pPathObj->m_GraphState.SetLineWidth(2.000000000000000000001); pPathObj->Transform(CFX_Matrix(1, 0, 0, 1, 432, 500000000000000.000002)); - pPathObj->set_filltype(FXFILL_WINDING); + pPathObj->set_filltype(CFX_FillRenderOptions::FillType::kWinding); pPathObj->path().AppendPoint(CFX_PointF(0.000000000000000000001f, 4.67f), - FXPT_TYPE::MoveTo, false); + CFX_Path::Point::Type::kMove); pPathObj->path().AppendPoint( CFX_PointF(0.000000000000000000001, 100000000000000.000002), - FXPT_TYPE::LineTo, false); + CFX_Path::Point::Type::kLine); pPathObj->path().AppendPoint(CFX_PointF(0.0000000000001f, 3.15f), - FXPT_TYPE::BezierTo, false); - pPathObj->path().AppendPoint(CFX_PointF(3.57f, 2.98f), FXPT_TYPE::BezierTo, - false); - pPathObj->path().AppendPoint( + CFX_Path::Point::Type::kBezier); + pPathObj->path().AppendPoint(CFX_PointF(3.57f, 2.98f), + CFX_Path::Point::Type::kBezier); + pPathObj->path().AppendPointAndClose( CFX_PointF(53.4f, 5000000000000000000.00000000000000004), - FXPT_TYPE::BezierTo, true); + CFX_Path::Point::Type::kBezier); auto dummy_page_dict = pdfium::MakeRetain<CPDF_Dictionary>(); - auto pTestPage = - pdfium::MakeRetain<CPDF_Page>(nullptr, dummy_page_dict.Get()); + auto pTestPage = pdfium::MakeRetain<CPDF_Page>(nullptr, dummy_page_dict); CPDF_PageContentGenerator generator(pTestPage.Get()); - std::ostringstream buf; + fxcrt::ostringstream buf; TestProcessPath(&generator, &buf, pPathObj.get()); EXPECT_EQ( @@ -144,33 +145,33 @@ } TEST_F(CPDF_PageContentGeneratorTest, ProcessPath) { - auto pPathObj = pdfium::MakeUnique<CPDF_PathObject>(); - pPathObj->set_filltype(FXFILL_WINDING); - pPathObj->path().AppendPoint(CFX_PointF(3.102f, 4.67f), FXPT_TYPE::MoveTo, - false); - pPathObj->path().AppendPoint(CFX_PointF(5.45f, 0.29f), FXPT_TYPE::LineTo, - false); - pPathObj->path().AppendPoint(CFX_PointF(4.24f, 3.15f), FXPT_TYPE::BezierTo, - false); - pPathObj->path().AppendPoint(CFX_PointF(4.65f, 2.98f), FXPT_TYPE::BezierTo, - false); - pPathObj->path().AppendPoint(CFX_PointF(3.456f, 0.24f), FXPT_TYPE::BezierTo, - false); - pPathObj->path().AppendPoint(CFX_PointF(10.6f, 11.15f), FXPT_TYPE::LineTo, - false); - pPathObj->path().AppendPoint(CFX_PointF(11, 12.5f), FXPT_TYPE::LineTo, false); - pPathObj->path().AppendPoint(CFX_PointF(11.46f, 12.67f), FXPT_TYPE::BezierTo, - false); - pPathObj->path().AppendPoint(CFX_PointF(11.84f, 12.96f), FXPT_TYPE::BezierTo, - false); - pPathObj->path().AppendPoint(CFX_PointF(12, 13.64f), FXPT_TYPE::BezierTo, - true); + auto pPathObj = std::make_unique<CPDF_PathObject>(); + pPathObj->set_filltype(CFX_FillRenderOptions::FillType::kWinding); + pPathObj->path().AppendPoint(CFX_PointF(3.102f, 4.67f), + CFX_Path::Point::Type::kMove); + pPathObj->path().AppendPoint(CFX_PointF(5.45f, 0.29f), + CFX_Path::Point::Type::kLine); + pPathObj->path().AppendPoint(CFX_PointF(4.24f, 3.15f), + CFX_Path::Point::Type::kBezier); + pPathObj->path().AppendPoint(CFX_PointF(4.65f, 2.98f), + CFX_Path::Point::Type::kBezier); + pPathObj->path().AppendPoint(CFX_PointF(3.456f, 0.24f), + CFX_Path::Point::Type::kBezier); + pPathObj->path().AppendPoint(CFX_PointF(10.6f, 11.15f), + CFX_Path::Point::Type::kLine); + pPathObj->path().AppendPoint(CFX_PointF(11, 12.5f), + CFX_Path::Point::Type::kLine); + pPathObj->path().AppendPoint(CFX_PointF(11.46f, 12.67f), + CFX_Path::Point::Type::kBezier); + pPathObj->path().AppendPoint(CFX_PointF(11.84f, 12.96f), + CFX_Path::Point::Type::kBezier); + pPathObj->path().AppendPointAndClose(CFX_PointF(12, 13.64f), + CFX_Path::Point::Type::kBezier); auto dummy_page_dict = pdfium::MakeRetain<CPDF_Dictionary>(); - auto pTestPage = - pdfium::MakeRetain<CPDF_Page>(nullptr, dummy_page_dict.Get()); + auto pTestPage = pdfium::MakeRetain<CPDF_Page>(nullptr, dummy_page_dict); CPDF_PageContentGenerator generator(pTestPage.Get()); - std::ostringstream buf; + fxcrt::ostringstream buf; TestProcessPath(&generator, &buf, pPathObj.get()); EXPECT_EQ( "q 1 0 0 1 0 0 cm 3.102 4.6700001 m 5.4499998 .28999999 l 4.2399998 " @@ -181,15 +182,17 @@ } TEST_F(CPDF_PageContentGeneratorTest, ProcessGraphics) { - auto pPathObj = pdfium::MakeUnique<CPDF_PathObject>(); + auto pPathObj = std::make_unique<CPDF_PathObject>(); pPathObj->set_stroke(true); - pPathObj->set_filltype(FXFILL_WINDING); - pPathObj->path().AppendPoint(CFX_PointF(1, 2), FXPT_TYPE::MoveTo, false); - pPathObj->path().AppendPoint(CFX_PointF(3, 4), FXPT_TYPE::LineTo, false); - pPathObj->path().AppendPoint(CFX_PointF(5, 6), FXPT_TYPE::LineTo, true); + pPathObj->set_filltype(CFX_FillRenderOptions::FillType::kWinding); + pPathObj->path().AppendPoint(CFX_PointF(1, 2), CFX_Path::Point::Type::kMove); + pPathObj->path().AppendPoint(CFX_PointF(3, 4), CFX_Path::Point::Type::kLine); + pPathObj->path().AppendPointAndClose(CFX_PointF(5, 6), + CFX_Path::Point::Type::kLine); static const std::vector<float> rgb = {0.5f, 0.7f, 0.35f}; - RetainPtr<CPDF_ColorSpace> pCS = CPDF_ColorSpace::GetStockCS(PDFCS_DEVICERGB); + RetainPtr<CPDF_ColorSpace> pCS = + CPDF_ColorSpace::GetStockCS(CPDF_ColorSpace::Family::kDeviceRGB); pPathObj->m_ColorState.SetFillColor(pCS, rgb); static const std::vector<float> rgb2 = {1, 0.9f, 0}; @@ -197,15 +200,13 @@ pPathObj->m_GeneralState.SetFillAlpha(0.5f); pPathObj->m_GeneralState.SetStrokeAlpha(0.8f); - auto pDoc = pdfium::MakeUnique<CPDF_Document>( - pdfium::MakeUnique<CPDF_DocRenderData>(), - pdfium::MakeUnique<CPDF_DocPageData>()); - + auto pDoc = std::make_unique<CPDF_TestDocument>(); pDoc->CreateNewDoc(); - CPDF_Dictionary* pPageDict = pDoc->CreateNewPage(0); + + RetainPtr<CPDF_Dictionary> pPageDict(pDoc->CreateNewPage(0)); auto pTestPage = pdfium::MakeRetain<CPDF_Page>(pDoc.get(), pPageDict); CPDF_PageContentGenerator generator(pTestPage.Get()); - std::ostringstream buf; + fxcrt::ostringstream buf; TestProcessPath(&generator, &buf, pPathObj.get()); ByteString pathString(buf); @@ -215,12 +216,12 @@ EXPECT_EQ(" gs 1 0 0 1 0 0 cm 1 2 m 3 4 l 5 6 l h B Q\n", pathString.Last(43)); ASSERT_GT(pathString.GetLength(), 91U); - CPDF_Dictionary* externalGS = + RetainPtr<const CPDF_Dictionary> externalGS = TestGetResource(&generator, "ExtGState", pathString.Substr(48, pathString.GetLength() - 91)); ASSERT_TRUE(externalGS); - EXPECT_EQ(0.5f, externalGS->GetNumberFor("ca")); - EXPECT_EQ(0.8f, externalGS->GetNumberFor("CA")); + EXPECT_EQ(0.5f, externalGS->GetFloatFor("ca")); + EXPECT_EQ(0.8f, externalGS->GetFloatFor("CA")); // Same path, now with a stroke. pPathObj->m_GraphState.SetLineWidth(10.5f); @@ -240,22 +241,20 @@ TEST_F(CPDF_PageContentGeneratorTest, ProcessStandardText) { // Checking font whose font dictionary is not yet indirect object. - auto pDoc = pdfium::MakeUnique<CPDF_Document>( - pdfium::MakeUnique<CPDF_DocRenderData>(), - pdfium::MakeUnique<CPDF_DocPageData>()); - + auto pDoc = std::make_unique<CPDF_TestDocument>(); pDoc->CreateNewDoc(); - CPDF_Dictionary* pPageDict = pDoc->CreateNewPage(0); + + RetainPtr<CPDF_Dictionary> pPageDict(pDoc->CreateNewPage(0)); auto pTestPage = pdfium::MakeRetain<CPDF_Page>(pDoc.get(), pPageDict); CPDF_PageContentGenerator generator(pTestPage.Get()); - auto pTextObj = pdfium::MakeUnique<CPDF_TextObject>(); - RetainPtr<CPDF_Font> pFont = - CPDF_Font::GetStockFont(pDoc.get(), "Times-Roman"); - pTextObj->m_TextState.SetFont(pFont); + auto pTextObj = std::make_unique<CPDF_TextObject>(); + pTextObj->m_TextState.SetFont( + CPDF_Font::GetStockFont(pDoc.get(), "Times-Roman")); pTextObj->m_TextState.SetFontSize(10.0f); static const std::vector<float> rgb = {0.5f, 0.7f, 0.35f}; - RetainPtr<CPDF_ColorSpace> pCS = CPDF_ColorSpace::GetStockCS(PDFCS_DEVICERGB); + RetainPtr<CPDF_ColorSpace> pCS = + CPDF_ColorSpace::GetStockCS(CPDF_ColorSpace::Family::kDeviceRGB); pTextObj->m_ColorState.SetFillColor(pCS, rgb); static const std::vector<float> rgb2 = {1, 0.9f, 0}; @@ -264,7 +263,7 @@ pTextObj->m_GeneralState.SetStrokeAlpha(0.8f); pTextObj->Transform(CFX_Matrix(1, 0, 0, 1, 100, 100)); pTextObj->SetText("Hello World"); - std::ostringstream buf; + fxcrt::ostringstream buf; TestProcessText(&generator, &buf, pTextObj.get()); ByteString textString(buf); auto firstResourceAt = textString.Find('/'); @@ -284,61 +283,70 @@ "q 0.501961 0.701961 0.34902 rg 1 0.901961 0 RG /"; // Color RGB values used are integers divided by 255. ByteString compareString2 = " gs BT 1 0 0 1 100 100 Tm /"; - ByteString compareString3 = " 10 Tf <48656C6C6F20576F726C64> Tj ET Q\n"; + ByteString compareString3 = " 10 Tf 0 Tr <48656C6C6F20576F726C64> Tj ET Q\n"; EXPECT_LT(compareString1.GetLength() + compareString2.GetLength() + compareString3.GetLength(), textString.GetLength()); EXPECT_EQ(compareString1, firstString.First(compareString1.GetLength())); EXPECT_EQ(compareString2, midString.Last(compareString2.GetLength())); EXPECT_EQ(compareString3, lastString.Last(compareString3.GetLength())); - CPDF_Dictionary* externalGS = TestGetResource( + RetainPtr<const CPDF_Dictionary> externalGS = TestGetResource( &generator, "ExtGState", midString.First(midString.GetLength() - compareString2.GetLength())); ASSERT_TRUE(externalGS); - EXPECT_EQ(0.5f, externalGS->GetNumberFor("ca")); - EXPECT_EQ(0.8f, externalGS->GetNumberFor("CA")); - CPDF_Dictionary* fontDict = TestGetResource( + EXPECT_EQ(0.5f, externalGS->GetFloatFor("ca")); + EXPECT_EQ(0.8f, externalGS->GetFloatFor("CA")); + RetainPtr<const CPDF_Dictionary> fontDict = TestGetResource( &generator, "Font", lastString.First(lastString.GetLength() - compareString3.GetLength())); ASSERT_TRUE(fontDict); - EXPECT_EQ("Font", fontDict->GetStringFor("Type")); - EXPECT_EQ("Type1", fontDict->GetStringFor("Subtype")); - EXPECT_EQ("Times-Roman", fontDict->GetStringFor("BaseFont")); + EXPECT_EQ("Font", fontDict->GetNameFor("Type")); + EXPECT_EQ("Type1", fontDict->GetNameFor("Subtype")); + EXPECT_EQ("Times-Roman", fontDict->GetNameFor("BaseFont")); } TEST_F(CPDF_PageContentGeneratorTest, ProcessText) { // Checking font whose font dictionary is already an indirect object. - auto pDoc = pdfium::MakeUnique<CPDF_Document>( - pdfium::MakeUnique<CPDF_DocRenderData>(), - pdfium::MakeUnique<CPDF_DocPageData>()); + auto pDoc = std::make_unique<CPDF_TestDocument>(); pDoc->CreateNewDoc(); - CPDF_Dictionary* pPageDict = pDoc->CreateNewPage(0); + RetainPtr<CPDF_Dictionary> pPageDict(pDoc->CreateNewPage(0)); auto pTestPage = pdfium::MakeRetain<CPDF_Page>(pDoc.get(), pPageDict); CPDF_PageContentGenerator generator(pTestPage.Get()); - std::ostringstream buf; + fxcrt::ostringstream buf; { // Set the text object font and text - auto pTextObj = pdfium::MakeUnique<CPDF_TextObject>(); - CPDF_Dictionary* pDict = pDoc->NewIndirect<CPDF_Dictionary>(); + auto pTextObj = std::make_unique<CPDF_TextObject>(); + auto pDict = pDoc->NewIndirect<CPDF_Dictionary>(); pDict->SetNewFor<CPDF_Name>("Type", "Font"); pDict->SetNewFor<CPDF_Name>("Subtype", "TrueType"); RetainPtr<CPDF_Font> pFont = CPDF_Font::GetStockFont(pDoc.get(), "Arial"); pDict->SetNewFor<CPDF_Name>("BaseFont", pFont->GetBaseFontName()); - CPDF_Dictionary* pDesc = pDoc->NewIndirect<CPDF_Dictionary>(); + auto pDesc = pDoc->NewIndirect<CPDF_Dictionary>(); pDesc->SetNewFor<CPDF_Name>("Type", "FontDescriptor"); pDesc->SetNewFor<CPDF_Name>("FontName", pFont->GetBaseFontName()); pDict->SetNewFor<CPDF_Reference>("FontDescriptor", pDoc.get(), pDesc->GetObjNum()); - RetainPtr<CPDF_Font> pLoadedFont = - CPDF_DocPageData::FromDocument(pDoc.get())->GetFont(pDict); - pTextObj->m_TextState.SetFont(pLoadedFont); + pTextObj->m_TextState.SetFont( + CPDF_DocPageData::FromDocument(pDoc.get())->GetFont(pDict)); pTextObj->m_TextState.SetFontSize(15.5f); pTextObj->SetText("I am indirect"); + pTextObj->SetTextRenderMode(TextRenderingMode::MODE_FILL_CLIP); + + // Add a clipping path. + auto pPath = std::make_unique<CPDF_Path>(); + pPath->AppendPoint(CFX_PointF(0, 0), CFX_Path::Point::Type::kMove); + pPath->AppendPoint(CFX_PointF(5, 0), CFX_Path::Point::Type::kLine); + pPath->AppendPoint(CFX_PointF(5, 4), CFX_Path::Point::Type::kLine); + pPath->AppendPointAndClose(CFX_PointF(0, 4), CFX_Path::Point::Type::kLine); + pTextObj->m_ClipPath.Emplace(); + pTextObj->m_ClipPath.AppendPath(*pPath, + CFX_FillRenderOptions::FillType::kEvenOdd); + TestProcessText(&generator, &buf, pTextObj.get()); } @@ -350,75 +358,68 @@ ByteString lastString = textString.Last(textString.GetLength() - firstResourceAt.value()); // q and Q must be outside the BT .. ET operations - ByteString compareString1 = "q BT 1 0 0 1 0 0 Tm /"; - ByteString compareString2 = " 15.5 Tf <4920616D20696E646972656374> Tj ET Q\n"; + ByteString compareString1 = "q 0 0 5 4 re W* n BT 1 0 0 1 0 0 Tm /"; + ByteString compareString2 = + " 15.5 Tf 4 Tr <4920616D20696E646972656374> Tj ET Q\n"; EXPECT_LT(compareString1.GetLength() + compareString2.GetLength(), textString.GetLength()); EXPECT_EQ(compareString1, textString.First(compareString1.GetLength())); EXPECT_EQ(compareString2, textString.Last(compareString2.GetLength())); - CPDF_Dictionary* fontDict = TestGetResource( + RetainPtr<const CPDF_Dictionary> fontDict = TestGetResource( &generator, "Font", textString.Substr(compareString1.GetLength(), textString.GetLength() - compareString1.GetLength() - compareString2.GetLength())); ASSERT_TRUE(fontDict); EXPECT_TRUE(fontDict->GetObjNum()); - EXPECT_EQ("Font", fontDict->GetStringFor("Type")); - EXPECT_EQ("TrueType", fontDict->GetStringFor("Subtype")); - EXPECT_EQ("Helvetica", fontDict->GetStringFor("BaseFont")); - CPDF_Dictionary* fontDesc = fontDict->GetDictFor("FontDescriptor"); + EXPECT_EQ("Font", fontDict->GetNameFor("Type")); + EXPECT_EQ("TrueType", fontDict->GetNameFor("Subtype")); + EXPECT_EQ("Helvetica", fontDict->GetNameFor("BaseFont")); + RetainPtr<const CPDF_Dictionary> fontDesc = + fontDict->GetDictFor("FontDescriptor"); ASSERT_TRUE(fontDesc); EXPECT_TRUE(fontDesc->GetObjNum()); - EXPECT_EQ("FontDescriptor", fontDesc->GetStringFor("Type")); - EXPECT_EQ("Helvetica", fontDesc->GetStringFor("FontName")); + EXPECT_EQ("FontDescriptor", fontDesc->GetNameFor("Type")); + EXPECT_EQ("Helvetica", fontDesc->GetNameFor("FontName")); } TEST_F(CPDF_PageContentGeneratorTest, ProcessEmptyForm) { - auto pDoc = pdfium::MakeUnique<CPDF_Document>( - pdfium::MakeUnique<CPDF_DocRenderData>(), - pdfium::MakeUnique<CPDF_DocPageData>()); + auto pDoc = std::make_unique<CPDF_TestDocument>(); pDoc->CreateNewDoc(); - auto pDict = pdfium::MakeRetain<CPDF_Dictionary>(); - auto pStream = pdfium::MakeRetain<CPDF_Stream>(nullptr, 0, std::move(pDict)); + auto pStream = + pdfium::MakeRetain<CPDF_Stream>(pdfium::MakeRetain<CPDF_Dictionary>()); // Create an empty form. - auto pTestForm = - pdfium::MakeUnique<CPDF_Form>(pDoc.get(), nullptr, pStream.Get()); + auto pTestForm = std::make_unique<CPDF_Form>(pDoc.get(), nullptr, pStream); pTestForm->ParseContent(); ASSERT_EQ(CPDF_PageObjectHolder::ParseState::kParsed, pTestForm->GetParseState()); // The generated stream for the empty form should be an empty string. CPDF_PageContentGenerator generator(pTestForm.get()); - std::ostringstream buf; + fxcrt::ostringstream buf; generator.ProcessPageObjects(&buf); EXPECT_EQ("", ByteString(buf)); } TEST_F(CPDF_PageContentGeneratorTest, ProcessFormWithPath) { - auto pDoc = pdfium::MakeUnique<CPDF_Document>( - pdfium::MakeUnique<CPDF_DocRenderData>(), - pdfium::MakeUnique<CPDF_DocPageData>()); + auto pDoc = std::make_unique<CPDF_TestDocument>(); pDoc->CreateNewDoc(); - auto pDict = pdfium::MakeRetain<CPDF_Dictionary>(); - const char content[] = + static constexpr uint8_t kContents[] = "q 1 0 0 1 0 0 cm 3.102 4.6700001 m 5.4500012 .28999999 " "l 4.2399998 3.1499999 4.65 2.98 3.456 0.24 c 3.102 4.6700001 l h f Q\n"; - size_t buf_len = FX_ArraySize(content); - std::unique_ptr<uint8_t, FxFreeDeleter> buf(FX_Alloc(uint8_t, buf_len)); - memcpy(buf.get(), content, buf_len); - auto pStream = pdfium::MakeRetain<CPDF_Stream>(std::move(buf), buf_len, - std::move(pDict)); + auto pStream = pdfium::MakeRetain<CPDF_Stream>( + DataVector<uint8_t>(std::begin(kContents), std::end(kContents)), + pdfium::MakeRetain<CPDF_Dictionary>()); // Create a form with a non-empty stream. - auto pTestForm = - pdfium::MakeUnique<CPDF_Form>(pDoc.get(), nullptr, pStream.Get()); + auto pTestForm = std::make_unique<CPDF_Form>(pDoc.get(), nullptr, pStream); pTestForm->ParseContent(); ASSERT_EQ(CPDF_PageObjectHolder::ParseState::kParsed, pTestForm->GetParseState()); CPDF_PageContentGenerator generator(pTestForm.get()); - std::ostringstream process_buf; + fxcrt::ostringstream process_buf; generator.ProcessPageObjects(&process_buf); EXPECT_STREQ( "q 1 0 0 1 0 0 cm 3.102 4.6700001 m 5.4500012 .28999999 l 4.2399998 3.14"
diff --git a/core/fpdfapi/edit/cpdf_pagecontentmanager.cpp b/core/fpdfapi/edit/cpdf_pagecontentmanager.cpp index 35a8acd..4be22e6 100644 --- a/core/fpdfapi/edit/cpdf_pagecontentmanager.cpp +++ b/core/fpdfapi/edit/cpdf_pagecontentmanager.cpp
@@ -1,11 +1,16 @@ -// Copyright 2018 PDFium Authors. All rights reserved. +// Copyright 2018 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "core/fpdfapi/edit/cpdf_pagecontentmanager.h" +#include <stdint.h> + #include <map> #include <numeric> +#include <set> +#include <sstream> +#include <utility> #include <vector> #include "core/fpdfapi/page/cpdf_pageobject.h" @@ -15,87 +20,155 @@ #include "core/fpdfapi/parser/cpdf_document.h" #include "core/fpdfapi/parser/cpdf_reference.h" #include "core/fpdfapi/parser/cpdf_stream.h" +#include "core/fpdfapi/parser/object_tree_traversal_util.h" +#include "third_party/abseil-cpp/absl/types/variant.h" +#include "third_party/base/check.h" +#include "third_party/base/containers/adapters.h" +#include "third_party/base/containers/contains.h" +#include "third_party/base/numerics/safe_conversions.h" CPDF_PageContentManager::CPDF_PageContentManager( - const CPDF_PageObjectHolder* obj_holder) - : obj_holder_(obj_holder), doc_(obj_holder_->GetDocument()) { - CPDF_Dictionary* page_dict = obj_holder_->GetDict(); - CPDF_Object* contents_obj = page_dict->GetObjectFor("Contents"); - CPDF_Array* contents_array = ToArray(contents_obj); + CPDF_PageObjectHolder* page_obj_holder, + CPDF_Document* document) + : page_obj_holder_(page_obj_holder), + document_(document), + objects_with_multi_refs_(GetObjectsWithMultipleReferences(document_)) { + RetainPtr<CPDF_Dictionary> page_dict = page_obj_holder_->GetMutableDict(); + RetainPtr<CPDF_Object> contents_obj = + page_dict->GetMutableObjectFor("Contents"); + RetainPtr<CPDF_Array> contents_array = ToArray(contents_obj); if (contents_array) { - contents_array_.Reset(contents_array); + CHECK(contents_array->IsInline()); + contents_ = std::move(contents_array); return; } - CPDF_Reference* contents_reference = ToReference(contents_obj); + RetainPtr<CPDF_Reference> contents_reference = ToReference(contents_obj); if (contents_reference) { - CPDF_Object* indirect_obj = contents_reference->GetDirect(); + RetainPtr<CPDF_Object> indirect_obj = + contents_reference->GetMutableDirect(); if (!indirect_obj) return; - contents_array = indirect_obj->AsArray(); - if (contents_array) - contents_array_.Reset(contents_array); - else if (indirect_obj->IsStream()) - contents_stream_.Reset(indirect_obj->AsStream()); + contents_array.Reset(indirect_obj->AsMutableArray()); + if (contents_array) { + if (pdfium::Contains(objects_with_multi_refs_, + contents_array->GetObjNum())) { + RetainPtr<CPDF_Array> cloned_contents_array = + pdfium::WrapRetain(contents_array->Clone()->AsMutableArray()); + page_dict->SetFor("Contents", cloned_contents_array); + contents_ = std::move(cloned_contents_array); + } else { + contents_ = std::move(contents_array); + } + } else if (indirect_obj->IsStream()) { + contents_ = pdfium::WrapRetain(indirect_obj->AsMutableStream()); + } } } -CPDF_PageContentManager::~CPDF_PageContentManager() = default; - -CPDF_Stream* CPDF_PageContentManager::GetStreamByIndex(size_t stream_index) { - if (contents_stream_) - return stream_index == 0 ? contents_stream_.Get() : nullptr; - - if (contents_array_) { - CPDF_Reference* stream_reference = - ToReference(contents_array_->GetObjectAt(stream_index)); - if (!stream_reference) - return nullptr; - - return stream_reference->GetDirect()->AsStream(); - } - - return nullptr; +CPDF_PageContentManager::~CPDF_PageContentManager() { + ExecuteScheduledRemovals(); } -size_t CPDF_PageContentManager::AddStream(std::ostringstream* buf) { - CPDF_Stream* new_stream = doc_->NewIndirect<CPDF_Stream>(); +RetainPtr<CPDF_Stream> CPDF_PageContentManager::GetStreamByIndex( + size_t stream_index) { + RetainPtr<CPDF_Stream> contents_stream = GetContentsStream(); + if (contents_stream) { + return stream_index == 0 ? contents_stream : nullptr; + } + + RetainPtr<CPDF_Array> contents_array = GetContentsArray(); + if (!contents_array) { + return nullptr; + } + + RetainPtr<CPDF_Reference> stream_reference = + ToReference(contents_array->GetMutableObjectAt(stream_index)); + if (!stream_reference) + return nullptr; + + return ToStream(stream_reference->GetMutableDirect()); +} + +size_t CPDF_PageContentManager::AddStream(fxcrt::ostringstream* buf) { + auto new_stream = document_->NewIndirect<CPDF_Stream>(); new_stream->SetDataFromStringstream(buf); // If there is one Content stream (not in an array), now there will be two, so // create an array with the old and the new one. The new one's index is 1. - if (contents_stream_) { - CPDF_Array* new_contents_array = doc_->NewIndirect<CPDF_Array>(); - new_contents_array->AddNew<CPDF_Reference>(doc_.Get(), - contents_stream_->GetObjNum()); - new_contents_array->AddNew<CPDF_Reference>(doc_.Get(), - new_stream->GetObjNum()); + RetainPtr<CPDF_Stream> contents_stream = GetContentsStream(); + if (contents_stream) { + auto new_contents_array = document_->NewIndirect<CPDF_Array>(); + new_contents_array->AppendNew<CPDF_Reference>(document_, + contents_stream->GetObjNum()); + new_contents_array->AppendNew<CPDF_Reference>(document_, + new_stream->GetObjNum()); - CPDF_Dictionary* page_dict = obj_holder_->GetDict(); - page_dict->SetNewFor<CPDF_Reference>("Contents", doc_.Get(), + RetainPtr<CPDF_Dictionary> page_dict = page_obj_holder_->GetMutableDict(); + page_dict->SetNewFor<CPDF_Reference>("Contents", document_, new_contents_array->GetObjNum()); - contents_array_.Reset(new_contents_array); - contents_stream_ = nullptr; + contents_ = std::move(new_contents_array); return 1; } // If there is an array, just add the new stream to it, at the last position. - if (contents_array_) { - contents_array_->AddNew<CPDF_Reference>(doc_.Get(), - new_stream->GetObjNum()); - return contents_array_->size() - 1; + RetainPtr<CPDF_Array> contents_array = GetContentsArray(); + if (contents_array) { + contents_array->AppendNew<CPDF_Reference>(document_, + new_stream->GetObjNum()); + return contents_array->size() - 1; } // There were no Contents, so add the new stream as the single Content stream. // Its index is 0. - CPDF_Dictionary* page_dict = obj_holder_->GetDict(); - page_dict->SetNewFor<CPDF_Reference>("Contents", doc_.Get(), + RetainPtr<CPDF_Dictionary> page_dict = page_obj_holder_->GetMutableDict(); + page_dict->SetNewFor<CPDF_Reference>("Contents", document_, new_stream->GetObjNum()); - contents_stream_.Reset(new_stream); + contents_ = std::move(new_stream); return 0; } +void CPDF_PageContentManager::UpdateStream(size_t stream_index, + fxcrt::ostringstream* buf) { + // If `buf` is now empty, remove the stream instead of setting the data. + if (buf->tellp() <= 0) { + ScheduleRemoveStreamByIndex(stream_index); + return; + } + + RetainPtr<CPDF_Stream> existing_stream = GetStreamByIndex(stream_index); + CHECK(existing_stream); + if (!pdfium::Contains(objects_with_multi_refs_, + existing_stream->GetObjNum())) { + existing_stream->SetDataFromStringstreamAndRemoveFilter(buf); + return; + } + + if (GetContentsStream()) { + auto new_stream = document_->NewIndirect<CPDF_Stream>(); + new_stream->SetDataFromStringstream(buf); + RetainPtr<CPDF_Dictionary> page_dict = page_obj_holder_->GetMutableDict(); + page_dict->SetNewFor<CPDF_Reference>("Contents", document_, + new_stream->GetObjNum()); + } + + RetainPtr<CPDF_Array> contents_array = GetContentsArray(); + if (!contents_array) { + return; + } + + RetainPtr<CPDF_Reference> stream_reference = + ToReference(contents_array->GetMutableObjectAt(stream_index)); + if (!stream_reference) { + return; + } + + auto new_stream = document_->NewIndirect<CPDF_Stream>(); + new_stream->SetDataFromStringstream(buf); + stream_reference->SetRef(document_, new_stream->GetObjNum()); +} + void CPDF_PageContentManager::ScheduleRemoveStreamByIndex(size_t stream_index) { streams_to_remove_.insert(stream_index); } @@ -104,49 +177,72 @@ // This method assumes there are no dirty streams in the // CPDF_PageObjectHolder. If there were any, their indexes would need to be // updated. - // Since this is only called by CPDF_PageContentGenerator::GenerateContent(), - // which cleans up the dirty streams first, this should always be true. - ASSERT(!obj_holder_->HasDirtyStreams()); + // Since CPDF_PageContentManager is only instantiated in + // CPDF_PageContentGenerator::GenerateContent(), which cleans up the dirty + // streams first, this should always be true. + DCHECK(!page_obj_holder_->HasDirtyStreams()); - if (contents_stream_) { - // Only stream that can be removed is 0. - if (streams_to_remove_.find(0) != streams_to_remove_.end()) { - CPDF_Dictionary* page_dict = obj_holder_->GetDict(); - page_dict->RemoveFor("Contents"); - contents_stream_ = nullptr; - } - } else if (contents_array_) { - // Initialize a vector with the old stream indexes. This will be used to - // build a map from the old to the new indexes. - std::vector<size_t> streams_left(contents_array_->size()); - std::iota(streams_left.begin(), streams_left.end(), 0); - - // In reverse order so as to not change the indexes in the middle of the - // loop, remove the streams. - for (auto it = streams_to_remove_.rbegin(); it != streams_to_remove_.rend(); - ++it) { - size_t stream_index = *it; - contents_array_->RemoveAt(stream_index); - streams_left.erase(streams_left.begin() + stream_index); - } - - // Create a mapping from the old to the new stream indexes, shifted due to - // the deletion of the |streams_to_remove_|. - std::map<int32_t, size_t> stream_index_mapping; - for (size_t i = 0; i < streams_left.size(); ++i) - stream_index_mapping[streams_left[i]] = i; - - // Update the page objects' content stream indexes. - for (const auto& obj : *obj_holder_) { - int32_t old_stream_index = obj->GetContentStream(); - size_t new_stream_index = stream_index_mapping[old_stream_index]; - obj->SetContentStream(new_stream_index); - } - - // Even if there is a single content stream now, keep the array with a - // single element. It's valid, a second stream might be added soon, and the - // complexity of removing it is not worth it. + if (streams_to_remove_.empty()) { + return; } - streams_to_remove_.clear(); + RetainPtr<CPDF_Stream> contents_stream = GetContentsStream(); + if (contents_stream) { + // Only stream that can be removed is 0. + if (streams_to_remove_.find(0) != streams_to_remove_.end()) { + RetainPtr<CPDF_Dictionary> page_dict = page_obj_holder_->GetMutableDict(); + page_dict->RemoveFor("Contents"); + } + return; + } + + RetainPtr<CPDF_Array> contents_array = GetContentsArray(); + if (!contents_array) { + return; + } + + // Initialize a vector with the old stream indexes. This will be used to build + // a map from the old to the new indexes. + std::vector<size_t> streams_left(contents_array->size()); + std::iota(streams_left.begin(), streams_left.end(), 0); + + // In reverse order so as to not change the indexes in the middle of the loop, + // remove the streams. + for (size_t stream_index : pdfium::base::Reversed(streams_to_remove_)) { + contents_array->RemoveAt(stream_index); + streams_left.erase(streams_left.begin() + stream_index); + } + + // Create a mapping from the old to the new stream indexes, shifted due to the + // deletion of the |streams_to_remove_|. + std::map<size_t, size_t> stream_index_mapping; + for (size_t i = 0; i < streams_left.size(); ++i) { + stream_index_mapping[streams_left[i]] = i; + } + + // Update the page objects' content stream indexes. + for (const auto& obj : *page_obj_holder_) { + int32_t old_stream_index = obj->GetContentStream(); + int32_t new_stream_index = pdfium::base::checked_cast<int32_t>( + stream_index_mapping[old_stream_index]); + obj->SetContentStream(new_stream_index); + } + + // Even if there is a single content stream now, keep the array with a single + // element. It's valid, a second stream might be added in the near future, and + // the complexity of removing it is not worth it. +} + +RetainPtr<CPDF_Stream> CPDF_PageContentManager::GetContentsStream() { + if (absl::holds_alternative<RetainPtr<CPDF_Stream>>(contents_)) { + return absl::get<RetainPtr<CPDF_Stream>>(contents_); + } + return nullptr; +} + +RetainPtr<CPDF_Array> CPDF_PageContentManager::GetContentsArray() { + if (absl::holds_alternative<RetainPtr<CPDF_Array>>(contents_)) { + return absl::get<RetainPtr<CPDF_Array>>(contents_); + } + return nullptr; }
diff --git a/core/fpdfapi/edit/cpdf_pagecontentmanager.h b/core/fpdfapi/edit/cpdf_pagecontentmanager.h index 2e2b225..5785fc3 100644 --- a/core/fpdfapi/edit/cpdf_pagecontentmanager.h +++ b/core/fpdfapi/edit/cpdf_pagecontentmanager.h
@@ -1,49 +1,60 @@ -// Copyright 2018 PDFium Authors. All rights reserved. +// Copyright 2018 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #ifndef CORE_FPDFAPI_EDIT_CPDF_PAGECONTENTMANAGER_H_ #define CORE_FPDFAPI_EDIT_CPDF_PAGECONTENTMANAGER_H_ -#include <set> -#include <sstream> +#include <stdint.h> +#include <set> + +#include "core/fxcrt/fx_string_wrappers.h" #include "core/fxcrt/retain_ptr.h" #include "core/fxcrt/unowned_ptr.h" +#include "third_party/abseil-cpp/absl/types/variant.h" class CPDF_Array; class CPDF_Document; -class CPDF_Object; -class CPDF_Stream; class CPDF_PageObjectHolder; +class CPDF_Stream; class CPDF_PageContentManager { public: - explicit CPDF_PageContentManager(const CPDF_PageObjectHolder* obj_holder); + CPDF_PageContentManager(CPDF_PageObjectHolder* page_obj_holder, + CPDF_Document* document); ~CPDF_PageContentManager(); - // Gets the Content stream at a given index. If Contents is a single stream - // rather than an array, it is considered to be at index 0. - CPDF_Stream* GetStreamByIndex(size_t stream_index); - // Adds a new Content stream. Its index in the array will be returned, or 0 // if Contents is not an array, but only a single stream. - size_t AddStream(std::ostringstream* buf); + size_t AddStream(fxcrt::ostringstream* buf); - // Schedule the removal of the Content stream at a given index. It will be - // removed when ExecuteScheduledRemovals() is called. + // Changes the stream at `stream_index` to contain the data in `buf`. If `buf` + // is empty, then schedule the removal of the stream instead. + void UpdateStream(size_t stream_index, fxcrt::ostringstream* buf); + + private: + // Gets the Content stream at a given index. If Contents is a single stream + // rather than an array, it is retrievable at index 0. + RetainPtr<CPDF_Stream> GetStreamByIndex(size_t stream_index); + + // Schedules the removal of the Content stream at a given index. It will be + // removed upon CPDF_PageContentManager destruction. void ScheduleRemoveStreamByIndex(size_t stream_index); - // Remove all Content streams for which ScheduleRemoveStreamByIndex() was + // Removes all Content streams for which ScheduleRemoveStreamByIndex() was // called. Update the content stream of all page objects with the shifted // indexes. void ExecuteScheduledRemovals(); - private: - UnownedPtr<const CPDF_PageObjectHolder> const obj_holder_; - UnownedPtr<CPDF_Document> const doc_; - RetainPtr<CPDF_Array> contents_array_; - RetainPtr<CPDF_Stream> contents_stream_; + RetainPtr<CPDF_Stream> GetContentsStream(); + RetainPtr<CPDF_Array> GetContentsArray(); + + UnownedPtr<CPDF_PageObjectHolder> const page_obj_holder_; + UnownedPtr<CPDF_Document> const document_; + const std::set<uint32_t> objects_with_multi_refs_; + // When holding a CPDF_Stream, the pointer may be null. + absl::variant<RetainPtr<CPDF_Stream>, RetainPtr<CPDF_Array>> contents_; std::set<size_t> streams_to_remove_; };
diff --git a/core/fpdfapi/edit/cpdf_stringarchivestream.cpp b/core/fpdfapi/edit/cpdf_stringarchivestream.cpp index 4840db8..4d9f7f2 100644 --- a/core/fpdfapi/edit/cpdf_stringarchivestream.cpp +++ b/core/fpdfapi/edit/cpdf_stringarchivestream.cpp
@@ -1,35 +1,24 @@ -// Copyright 2018 PDFium Authors. All rights reserved. +// Copyright 2018 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "core/fpdfapi/edit/cpdf_stringarchivestream.h" -CPDF_StringArchiveStream::CPDF_StringArchiveStream(std::ostringstream* stream) +#include <sstream> + +#include "third_party/base/notreached.h" + +CPDF_StringArchiveStream::CPDF_StringArchiveStream(fxcrt::ostringstream* stream) : stream_(stream) {} -CPDF_StringArchiveStream::~CPDF_StringArchiveStream() {} - -bool CPDF_StringArchiveStream::WriteByte(uint8_t byte) { - NOTREACHED(); - return false; -} - -bool CPDF_StringArchiveStream::WriteDWord(uint32_t i) { - NOTREACHED(); - return false; -} +CPDF_StringArchiveStream::~CPDF_StringArchiveStream() = default; FX_FILESIZE CPDF_StringArchiveStream::CurrentOffset() const { NOTREACHED(); return false; } -bool CPDF_StringArchiveStream::WriteBlock(const void* pData, size_t size) { - stream_->write(static_cast<const char*>(pData), size); - return true; -} - -bool CPDF_StringArchiveStream::WriteString(ByteStringView str) { - stream_->write(str.unterminated_c_str(), str.GetLength()); +bool CPDF_StringArchiveStream::WriteBlock(pdfium::span<const uint8_t> buffer) { + stream_->write(reinterpret_cast<const char*>(buffer.data()), buffer.size()); return true; }
diff --git a/core/fpdfapi/edit/cpdf_stringarchivestream.h b/core/fpdfapi/edit/cpdf_stringarchivestream.h index 59d168f..1306343 100644 --- a/core/fpdfapi/edit/cpdf_stringarchivestream.h +++ b/core/fpdfapi/edit/cpdf_stringarchivestream.h
@@ -1,4 +1,4 @@ -// Copyright 2018 PDFium Authors. All rights reserved. +// Copyright 2018 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -6,21 +6,19 @@ #define CORE_FPDFAPI_EDIT_CPDF_STRINGARCHIVESTREAM_H_ #include "core/fxcrt/fx_stream.h" +#include "core/fxcrt/fx_string_wrappers.h" class CPDF_StringArchiveStream final : public IFX_ArchiveStream { public: - explicit CPDF_StringArchiveStream(std::ostringstream* stream); + explicit CPDF_StringArchiveStream(fxcrt::ostringstream* stream); ~CPDF_StringArchiveStream() override; - // IFX_ArchiveStream - bool WriteByte(uint8_t byte) override; - bool WriteDWord(uint32_t i) override; + // IFX_ArchiveStream: + bool WriteBlock(pdfium::span<const uint8_t> buffer) override; FX_FILESIZE CurrentOffset() const override; - bool WriteBlock(const void* pData, size_t size) override; - bool WriteString(ByteStringView str) override; private: - std::ostringstream* stream_; + fxcrt::ostringstream* stream_; }; #endif // CORE_FPDFAPI_EDIT_CPDF_STRINGARCHIVESTREAM_H_
diff --git a/core/fpdfapi/font/BUILD.gn b/core/fpdfapi/font/BUILD.gn index c30269a..ce89433 100644 --- a/core/fpdfapi/font/BUILD.gn +++ b/core/fpdfapi/font/BUILD.gn
@@ -1,4 +1,4 @@ -# Copyright 2018 The PDFium Authors. All rights reserved. +# Copyright 2018 The PDFium Authors # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. @@ -17,8 +17,6 @@ "cpdf_cidfont.h", "cpdf_cmap.cpp", "cpdf_cmap.h", - "cpdf_cmapmanager.cpp", - "cpdf_cmapmanager.h", "cpdf_cmapparser.cpp", "cpdf_cmapparser.h", "cpdf_font.cpp", @@ -40,17 +38,21 @@ "cpdf_type3font.cpp", "cpdf_type3font.h", ] - configs += [ "../../../:pdfium_core_config" ] + configs += [ + "../../../:pdfium_strict_config", + "../../../:pdfium_noshorten_config", + ] deps = [ + "../../../constants", "../../fxcrt", "../../fxge", "../cmaps", "../parser", ] - if (is_mac) { - libs = [ "CoreFoundation.framework" ] - } visibility = [ "../../../*" ] + if (is_mac) { + frameworks = [ "CoreFoundation.framework" ] + } } pdfium_unittest_source_set("unittests") { @@ -61,8 +63,9 @@ ] deps = [ ":font", - "../page", + "../page:unit_test_support", "../parser", + "../parser:unit_test_support", "../render", ] pdfium_root_dir = "../../../"
diff --git a/core/fpdfapi/font/cfx_cttgsubtable.cpp b/core/fpdfapi/font/cfx_cttgsubtable.cpp index 49f93dc..ae5a841 100644 --- a/core/fpdfapi/font/cfx_cttgsubtable.cpp +++ b/core/fpdfapi/font/cfx_cttgsubtable.cpp
@@ -1,4 +1,4 @@ -// Copyright 2014 PDFium Authors. All rights reserved. +// Copyright 2014 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -6,11 +6,14 @@ #include "core/fpdfapi/font/cfx_cttgsubtable.h" +#include <stdint.h> + #include <utility> +#include "core/fxcrt/data_vector.h" +#include "core/fxcrt/fx_system.h" +#include "core/fxcrt/stl_util.h" #include "core/fxge/cfx_fontmapper.h" -#include "third_party/base/ptr_util.h" -#include "third_party/base/stl_util.h" namespace { @@ -50,61 +53,63 @@ CFX_CTTGSUBTable::~CFX_CTTGSUBTable() = default; bool CFX_CTTGSUBTable::LoadGSUBTable(FT_Bytes gsub) { - if ((gsub[0] << 24u | gsub[1] << 16u | gsub[2] << 8u | gsub[3]) != 0x00010000) + if (FXSYS_UINT32_GET_MSBFIRST(gsub) != 0x00010000) return false; - return Parse(&gsub[gsub[4] << 8 | gsub[5]], &gsub[gsub[6] << 8 | gsub[7]], - &gsub[gsub[8] << 8 | gsub[9]]); + return Parse(&gsub[FXSYS_UINT16_GET_MSBFIRST(gsub + 4)], + &gsub[FXSYS_UINT16_GET_MSBFIRST(gsub + 6)], + &gsub[FXSYS_UINT16_GET_MSBFIRST(gsub + 8)]); } uint32_t CFX_CTTGSUBTable::GetVerticalGlyph(uint32_t glyphnum) const { - uint32_t vglyphnum = 0; for (uint32_t item : m_featureSet) { - if (GetVerticalGlyphSub(FeatureList[item], glyphnum, &vglyphnum)) - break; + absl::optional<uint32_t> result = + GetVerticalGlyphSub(FeatureList[item], glyphnum); + if (result.has_value()) + return result.value(); } - return vglyphnum; + return 0; } -bool CFX_CTTGSUBTable::GetVerticalGlyphSub(const TFeatureRecord& feature, - uint32_t glyphnum, - uint32_t* vglyphnum) const { +absl::optional<uint32_t> CFX_CTTGSUBTable::GetVerticalGlyphSub( + const TFeatureRecord& feature, + uint32_t glyphnum) const { for (int index : feature.LookupListIndices) { - if (!pdfium::IndexInBounds(LookupList, index)) + if (!fxcrt::IndexInBounds(LookupList, index)) continue; - if (LookupList[index].LookupType == 1 && - GetVerticalGlyphSub2(LookupList[index], glyphnum, vglyphnum)) { - return true; - } + if (LookupList[index].LookupType != 1) + continue; + absl::optional<uint32_t> result = + GetVerticalGlyphSub2(LookupList[index], glyphnum); + if (result.has_value()) + return result.value(); } - return false; + return absl::nullopt; } -bool CFX_CTTGSUBTable::GetVerticalGlyphSub2(const TLookup& lookup, - uint32_t glyphnum, - uint32_t* vglyphnum) const { +absl::optional<uint32_t> CFX_CTTGSUBTable::GetVerticalGlyphSub2( + const TLookup& lookup, + uint32_t glyphnum) const { for (const auto& subTable : lookup.SubTables) { switch (subTable->SubstFormat) { case 1: { auto* tbl1 = static_cast<TSubTable1*>(subTable.get()); if (GetCoverageIndex(tbl1->Coverage.get(), glyphnum) >= 0) { - *vglyphnum = glyphnum + tbl1->DeltaGlyphID; - return true; + return glyphnum + tbl1->DeltaGlyphID; } break; } case 2: { auto* tbl2 = static_cast<TSubTable2*>(subTable.get()); int index = GetCoverageIndex(tbl2->Coverage.get(), glyphnum); - if (pdfium::IndexInBounds(tbl2->Substitutes, index)) { - *vglyphnum = tbl2->Substitutes[index]; - return true; + if (fxcrt::IndexInBounds(tbl2->Substitutes, index)) { + return tbl2->Substitutes[index]; } break; } } } - return false; + return absl::nullopt; } int CFX_CTTGSUBTable::GetCoverageIndex(TCoverageFormatBase* Coverage, @@ -145,25 +150,25 @@ } int16_t CFX_CTTGSUBTable::GetInt16(FT_Bytes& p) const { - uint16_t ret = p[0] << 8 | p[1]; + uint16_t ret = FXSYS_UINT16_GET_MSBFIRST(p); p += 2; return *(int16_t*)&ret; } uint16_t CFX_CTTGSUBTable::GetUInt16(FT_Bytes& p) const { - uint16_t ret = p[0] << 8 | p[1]; + uint16_t ret = FXSYS_UINT16_GET_MSBFIRST(p); p += 2; return ret; } int32_t CFX_CTTGSUBTable::GetInt32(FT_Bytes& p) const { - uint32_t ret = p[0] << 24 | p[1] << 16 | p[2] << 8 | p[3]; + uint32_t ret = FXSYS_UINT32_GET_MSBFIRST(p); p += 4; return *(int32_t*)&ret; } uint32_t CFX_CTTGSUBTable::GetUInt32(FT_Bytes& p) const { - uint32_t ret = p[0] << 24 | p[1] << 16 | p[2] << 8 | p[3]; + uint32_t ret = FXSYS_UINT32_GET_MSBFIRST(p); p += 4; return ret; } @@ -200,7 +205,7 @@ FT_Bytes sp = raw; rec->LookupOrder = GetUInt16(sp); rec->ReqFeatureIndex = GetUInt16(sp); - rec->FeatureIndices = std::vector<uint16_t>(GetUInt16(sp)); + rec->FeatureIndices = DataVector<uint16_t>(GetUInt16(sp)); for (auto& element : rec->FeatureIndices) element = GetUInt16(sp); } @@ -217,7 +222,7 @@ void CFX_CTTGSUBTable::ParseFeature(FT_Bytes raw, TFeatureRecord* rec) { FT_Bytes sp = raw; rec->FeatureParams = GetUInt16(sp); - rec->LookupListIndices = std::vector<uint16_t>(GetUInt16(sp)); + rec->LookupListIndices = DataVector<uint16_t>(GetUInt16(sp)); for (auto& listIndex : rec->LookupListIndices) listIndex = GetUInt16(sp); } @@ -238,127 +243,117 @@ return; for (auto& subTable : rec->SubTables) - ParseSingleSubst(&raw[GetUInt16(sp)], &subTable); + subTable = ParseSingleSubst(&raw[GetUInt16(sp)]); } std::unique_ptr<CFX_CTTGSUBTable::TCoverageFormatBase> CFX_CTTGSUBTable::ParseCoverage(FT_Bytes raw) { FT_Bytes sp = raw; uint16_t format = GetUInt16(sp); - if (format == 1) { - auto rec = pdfium::MakeUnique<TCoverageFormat1>(); - ParseCoverageFormat1(raw, rec.get()); - return std::move(rec); - } - if (format == 2) { - auto rec = pdfium::MakeUnique<TCoverageFormat2>(); - ParseCoverageFormat2(raw, rec.get()); - return std::move(rec); - } + if (format == 1) + return ParseCoverageFormat1(raw); + if (format == 2) + return ParseCoverageFormat2(raw); return nullptr; } -void CFX_CTTGSUBTable::ParseCoverageFormat1(FT_Bytes raw, - TCoverageFormat1* rec) { +std::unique_ptr<CFX_CTTGSUBTable::TCoverageFormat1> +CFX_CTTGSUBTable::ParseCoverageFormat1(FT_Bytes raw) { FT_Bytes sp = raw; (void)GetUInt16(sp); - rec->GlyphArray = std::vector<uint16_t>(GetUInt16(sp)); + auto rec = std::make_unique<TCoverageFormat1>(GetUInt16(sp)); for (auto& glyph : rec->GlyphArray) glyph = GetUInt16(sp); + return rec; } -void CFX_CTTGSUBTable::ParseCoverageFormat2(FT_Bytes raw, - TCoverageFormat2* rec) { +std::unique_ptr<CFX_CTTGSUBTable::TCoverageFormat2> +CFX_CTTGSUBTable::ParseCoverageFormat2(FT_Bytes raw) { FT_Bytes sp = raw; (void)GetUInt16(sp); - rec->RangeRecords = std::vector<TRangeRecord>(GetUInt16(sp)); + auto rec = std::make_unique<TCoverageFormat2>(GetUInt16(sp)); for (auto& rangeRec : rec->RangeRecords) { rangeRec.Start = GetUInt16(sp); rangeRec.End = GetUInt16(sp); rangeRec.StartCoverageIndex = GetUInt16(sp); } + return rec; } -void CFX_CTTGSUBTable::ParseSingleSubst(FT_Bytes raw, - std::unique_ptr<TSubTableBase>* rec) { +std::unique_ptr<CFX_CTTGSUBTable::TSubTableBase> +CFX_CTTGSUBTable::ParseSingleSubst(FT_Bytes raw) { FT_Bytes sp = raw; - uint16_t Format = GetUInt16(sp); - switch (Format) { - case 1: - *rec = pdfium::MakeUnique<TSubTable1>(); - ParseSingleSubstFormat1(raw, static_cast<TSubTable1*>(rec->get())); - break; - case 2: - *rec = pdfium::MakeUnique<TSubTable2>(); - ParseSingleSubstFormat2(raw, static_cast<TSubTable2*>(rec->get())); - break; - } + uint16_t format = GetUInt16(sp); + if (format == 1) + return ParseSingleSubstFormat1(raw); + if (format == 2) + return ParseSingleSubstFormat2(raw); + return nullptr; } -void CFX_CTTGSUBTable::ParseSingleSubstFormat1(FT_Bytes raw, TSubTable1* rec) { +std::unique_ptr<CFX_CTTGSUBTable::TSubTable1> +CFX_CTTGSUBTable::ParseSingleSubstFormat1(FT_Bytes raw) { FT_Bytes sp = raw; GetUInt16(sp); uint16_t offset = GetUInt16(sp); + auto rec = std::make_unique<TSubTable1>(); rec->Coverage = ParseCoverage(&raw[offset]); rec->DeltaGlyphID = GetInt16(sp); + return rec; } -void CFX_CTTGSUBTable::ParseSingleSubstFormat2(FT_Bytes raw, TSubTable2* rec) { +std::unique_ptr<CFX_CTTGSUBTable::TSubTable2> +CFX_CTTGSUBTable::ParseSingleSubstFormat2(FT_Bytes raw) { FT_Bytes sp = raw; (void)GetUInt16(sp); uint16_t offset = GetUInt16(sp); + auto rec = std::make_unique<TSubTable2>(); rec->Coverage = ParseCoverage(&raw[offset]); - rec->Substitutes = std::vector<uint16_t>(GetUInt16(sp)); + rec->Substitutes = DataVector<uint16_t>(GetUInt16(sp)); for (auto& substitute : rec->Substitutes) substitute = GetUInt16(sp); + return rec; } -CFX_CTTGSUBTable::TLangSysRecord::TLangSysRecord() - : LangSysTag(0), LookupOrder(0), ReqFeatureIndex(0) {} +CFX_CTTGSUBTable::TLangSysRecord::TLangSysRecord() = default; -CFX_CTTGSUBTable::TLangSysRecord::~TLangSysRecord() {} +CFX_CTTGSUBTable::TLangSysRecord::~TLangSysRecord() = default; -CFX_CTTGSUBTable::TScriptRecord::TScriptRecord() - : ScriptTag(0), DefaultLangSys(0) {} +CFX_CTTGSUBTable::TScriptRecord::TScriptRecord() = default; -CFX_CTTGSUBTable::TScriptRecord::~TScriptRecord() {} +CFX_CTTGSUBTable::TScriptRecord::~TScriptRecord() = default; -CFX_CTTGSUBTable::TFeatureRecord::TFeatureRecord() - : FeatureTag(0), FeatureParams(0) {} +CFX_CTTGSUBTable::TFeatureRecord::TFeatureRecord() = default; -CFX_CTTGSUBTable::TFeatureRecord::~TFeatureRecord() {} +CFX_CTTGSUBTable::TFeatureRecord::~TFeatureRecord() = default; -CFX_CTTGSUBTable::TRangeRecord::TRangeRecord() - : Start(0), End(0), StartCoverageIndex(0) {} +CFX_CTTGSUBTable::TRangeRecord::TRangeRecord() = default; -CFX_CTTGSUBTable::TCoverageFormat1::TCoverageFormat1() { - CoverageFormat = 1; -} +CFX_CTTGSUBTable::TCoverageFormat1::TCoverageFormat1(size_t initial_size) + : TCoverageFormatBase(1), GlyphArray(initial_size) {} -CFX_CTTGSUBTable::TCoverageFormat1::~TCoverageFormat1() {} +CFX_CTTGSUBTable::TCoverageFormat1::~TCoverageFormat1() = default; -CFX_CTTGSUBTable::TCoverageFormat2::TCoverageFormat2() { - CoverageFormat = 2; -} +CFX_CTTGSUBTable::TCoverageFormat2::TCoverageFormat2(size_t initial_size) + : TCoverageFormatBase(2), RangeRecords(initial_size) {} -CFX_CTTGSUBTable::TCoverageFormat2::~TCoverageFormat2() {} +CFX_CTTGSUBTable::TCoverageFormat2::~TCoverageFormat2() = default; -CFX_CTTGSUBTable::TSubTableBase::TSubTableBase() {} +CFX_CTTGSUBTable::TDevice::TDevice() = default; -CFX_CTTGSUBTable::TSubTableBase::~TSubTableBase() {} +CFX_CTTGSUBTable::TSubTableBase::TSubTableBase(uint16_t format) + : SubstFormat(format) {} -CFX_CTTGSUBTable::TSubTable1::TSubTable1() { - SubstFormat = 1; -} +CFX_CTTGSUBTable::TSubTableBase::~TSubTableBase() = default; -CFX_CTTGSUBTable::TSubTable1::~TSubTable1() {} +CFX_CTTGSUBTable::TSubTable1::TSubTable1() : TSubTableBase(1) {} -CFX_CTTGSUBTable::TSubTable2::TSubTable2() { - SubstFormat = 2; -} +CFX_CTTGSUBTable::TSubTable1::~TSubTable1() = default; -CFX_CTTGSUBTable::TSubTable2::~TSubTable2() {} +CFX_CTTGSUBTable::TSubTable2::TSubTable2() : TSubTableBase(2) {} -CFX_CTTGSUBTable::TLookup::TLookup() : LookupType(0), LookupFlag(0) {} +CFX_CTTGSUBTable::TSubTable2::~TSubTable2() = default; -CFX_CTTGSUBTable::TLookup::~TLookup() {} +CFX_CTTGSUBTable::TLookup::TLookup() = default; + +CFX_CTTGSUBTable::TLookup::~TLookup() = default;
diff --git a/core/fpdfapi/font/cfx_cttgsubtable.h b/core/fpdfapi/font/cfx_cttgsubtable.h index 54e16b4..0555333 100644 --- a/core/fpdfapi/font/cfx_cttgsubtable.h +++ b/core/fpdfapi/font/cfx_cttgsubtable.h
@@ -1,4 +1,4 @@ -// Copyright 2014 PDFium Authors. All rights reserved. +// Copyright 2014 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -13,7 +13,9 @@ #include <set> #include <vector> -#include "core/fxge/fx_freetype.h" +#include "core/fxcrt/data_vector.h" +#include "core/fxge/freetype/fx_freetype.h" +#include "third_party/abseil-cpp/absl/types/optional.h" class CFX_CTTGSUBTable { public: @@ -27,18 +29,18 @@ TLangSysRecord(); ~TLangSysRecord(); - uint32_t LangSysTag; - uint16_t LookupOrder; - uint16_t ReqFeatureIndex; - std::vector<uint16_t> FeatureIndices; + uint32_t LangSysTag = 0; + uint16_t LookupOrder = 0; + uint16_t ReqFeatureIndex = 0; + DataVector<uint16_t> FeatureIndices; }; struct TScriptRecord { TScriptRecord(); ~TScriptRecord(); - uint32_t ScriptTag; - uint16_t DefaultLangSys; + uint32_t ScriptTag = 0; + uint16_t DefaultLangSys = 0; std::vector<TLangSysRecord> LangSysRecords; }; @@ -46,74 +48,76 @@ TFeatureRecord(); ~TFeatureRecord(); - uint32_t FeatureTag; - uint16_t FeatureParams; - std::vector<uint16_t> LookupListIndices; + uint32_t FeatureTag = 0; + uint16_t FeatureParams = 0; + DataVector<uint16_t> LookupListIndices; }; struct TRangeRecord { TRangeRecord(); - uint16_t Start; - uint16_t End; - uint16_t StartCoverageIndex; + uint16_t Start = 0; + uint16_t End = 0; + uint16_t StartCoverageIndex = 0; }; struct TCoverageFormatBase { + explicit TCoverageFormatBase(uint16_t format) : CoverageFormat(format) {} virtual ~TCoverageFormatBase() = default; - uint16_t CoverageFormat; + + const uint16_t CoverageFormat; }; struct TCoverageFormat1 final : public TCoverageFormatBase { - TCoverageFormat1(); + explicit TCoverageFormat1(size_t initial_size); ~TCoverageFormat1() override; - std::vector<uint16_t> GlyphArray; + DataVector<uint16_t> GlyphArray; }; struct TCoverageFormat2 final : public TCoverageFormatBase { - TCoverageFormat2(); + explicit TCoverageFormat2(size_t initial_size); ~TCoverageFormat2() override; std::vector<TRangeRecord> RangeRecords; }; struct TDevice { - TDevice() : StartSize(0), EndSize(0), DeltaFormat(0) {} + TDevice(); - uint16_t StartSize; - uint16_t EndSize; - uint16_t DeltaFormat; + uint16_t StartSize = 0; + uint16_t EndSize = 0; + uint16_t DeltaFormat = 0; }; struct TSubTableBase { - TSubTableBase(); + explicit TSubTableBase(uint16_t format); virtual ~TSubTableBase(); + const uint16_t SubstFormat; std::unique_ptr<TCoverageFormatBase> Coverage; - uint16_t SubstFormat; }; struct TSubTable1 final : public TSubTableBase { TSubTable1(); ~TSubTable1() override; - int16_t DeltaGlyphID; + int16_t DeltaGlyphID = 0; }; struct TSubTable2 final : public TSubTableBase { TSubTable2(); ~TSubTable2() override; - std::vector<uint16_t> Substitutes; + DataVector<uint16_t> Substitutes; }; struct TLookup { TLookup(); ~TLookup(); - uint16_t LookupType; - uint16_t LookupFlag; + uint16_t LookupType = 0; + uint16_t LookupFlag = 0; std::vector<std::unique_ptr<TSubTableBase>> SubTables; }; @@ -127,18 +131,16 @@ void ParseLookupList(FT_Bytes raw); void ParseLookup(FT_Bytes raw, TLookup* rec); std::unique_ptr<TCoverageFormatBase> ParseCoverage(FT_Bytes raw); - void ParseCoverageFormat1(FT_Bytes raw, TCoverageFormat1* rec); - void ParseCoverageFormat2(FT_Bytes raw, TCoverageFormat2* rec); - void ParseSingleSubst(FT_Bytes raw, std::unique_ptr<TSubTableBase>* rec); - void ParseSingleSubstFormat1(FT_Bytes raw, TSubTable1* rec); - void ParseSingleSubstFormat2(FT_Bytes raw, TSubTable2* rec); + std::unique_ptr<TCoverageFormat1> ParseCoverageFormat1(FT_Bytes raw); + std::unique_ptr<TCoverageFormat2> ParseCoverageFormat2(FT_Bytes raw); + std::unique_ptr<TSubTableBase> ParseSingleSubst(FT_Bytes raw); + std::unique_ptr<TSubTable1> ParseSingleSubstFormat1(FT_Bytes raw); + std::unique_ptr<TSubTable2> ParseSingleSubstFormat2(FT_Bytes raw); - bool GetVerticalGlyphSub(const TFeatureRecord& feature, - uint32_t glyphnum, - uint32_t* vglyphnum) const; - bool GetVerticalGlyphSub2(const TLookup& lookup, - uint32_t glyphnum, - uint32_t* vglyphnum) const; + absl::optional<uint32_t> GetVerticalGlyphSub(const TFeatureRecord& feature, + uint32_t glyphnum) const; + absl::optional<uint32_t> GetVerticalGlyphSub2(const TLookup& lookup, + uint32_t glyphnum) const; int GetCoverageIndex(TCoverageFormatBase* Coverage, uint32_t g) const; uint8_t GetUInt8(FT_Bytes& p) const;
diff --git a/core/fpdfapi/font/cfx_stockfontarray.cpp b/core/fpdfapi/font/cfx_stockfontarray.cpp index a8d8597..b6793ff 100644 --- a/core/fpdfapi/font/cfx_stockfontarray.cpp +++ b/core/fpdfapi/font/cfx_stockfontarray.cpp
@@ -1,4 +1,4 @@ -// Copyright 2017 PDFium Authors. All rights reserved. +// Copyright 2017 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -6,19 +6,22 @@ #include "core/fpdfapi/font/cfx_stockfontarray.h" -#include <memory> +#include <iterator> #include <utility> #include "core/fpdfapi/font/cpdf_font.h" #include "core/fpdfapi/parser/cpdf_dictionary.h" -#include "core/fxcrt/fx_memory.h" +#include "third_party/base/notreached.h" CFX_StockFontArray::CFX_StockFontArray() = default; CFX_StockFontArray::~CFX_StockFontArray() { - for (size_t i = 0; i < FX_ArraySize(m_StockFonts); ++i) { + for (size_t i = 0; i < std::size(m_StockFonts); ++i) { if (m_StockFonts[i]) { - RetainPtr<CPDF_Dictionary> destroy(m_StockFonts[i]->GetFontDict()); + // Ensure m_StockFonts[i]'s dict is cleared before releasing what + // may be the last reference to it. + RetainPtr<CPDF_Dictionary> destroy = + m_StockFonts[i]->GetMutableFontDict(); m_StockFonts[i]->ClearFontDict(); } } @@ -26,14 +29,14 @@ RetainPtr<CPDF_Font> CFX_StockFontArray::GetFont( CFX_FontMapper::StandardFont index) const { - if (index < FX_ArraySize(m_StockFonts)) + if (index < std::size(m_StockFonts)) return m_StockFonts[index]; NOTREACHED(); return nullptr; } void CFX_StockFontArray::SetFont(CFX_FontMapper::StandardFont index, - const RetainPtr<CPDF_Font>& pFont) { - if (index < FX_ArraySize(m_StockFonts)) - m_StockFonts[index] = pFont; + RetainPtr<CPDF_Font> pFont) { + if (index < std::size(m_StockFonts)) + m_StockFonts[index] = std::move(pFont); }
diff --git a/core/fpdfapi/font/cfx_stockfontarray.h b/core/fpdfapi/font/cfx_stockfontarray.h index 5e54704..30989d6 100644 --- a/core/fpdfapi/font/cfx_stockfontarray.h +++ b/core/fpdfapi/font/cfx_stockfontarray.h
@@ -1,4 +1,4 @@ -// Copyright 2017 PDFium Authors. All rights reserved. +// Copyright 2017 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -7,8 +7,6 @@ #ifndef CORE_FPDFAPI_FONT_CFX_STOCKFONTARRAY_H_ #define CORE_FPDFAPI_FONT_CFX_STOCKFONTARRAY_H_ -#include <memory> - #include "core/fxcrt/retain_ptr.h" #include "core/fxge/cfx_fontmapper.h" @@ -20,8 +18,7 @@ ~CFX_StockFontArray(); RetainPtr<CPDF_Font> GetFont(CFX_FontMapper::StandardFont index) const; - void SetFont(CFX_FontMapper::StandardFont index, - const RetainPtr<CPDF_Font>& pFont); + void SetFont(CFX_FontMapper::StandardFont index, RetainPtr<CPDF_Font> pFont); private: RetainPtr<CPDF_Font> m_StockFonts[14];
diff --git a/core/fpdfapi/font/cpdf_cid2unicodemap.cpp b/core/fpdfapi/font/cpdf_cid2unicodemap.cpp index abb23ac..fa14fe9 100644 --- a/core/fpdfapi/font/cpdf_cid2unicodemap.cpp +++ b/core/fpdfapi/font/cpdf_cid2unicodemap.cpp
@@ -1,4 +1,4 @@ -// Copyright 2017 PDFium Authors. All rights reserved. +// Copyright 2017 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file.
diff --git a/core/fpdfapi/font/cpdf_cid2unicodemap.h b/core/fpdfapi/font/cpdf_cid2unicodemap.h index e556917..5c18493 100644 --- a/core/fpdfapi/font/cpdf_cid2unicodemap.h +++ b/core/fpdfapi/font/cpdf_cid2unicodemap.h
@@ -1,4 +1,4 @@ -// Copyright 2017 PDFium Authors. All rights reserved. +// Copyright 2017 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file.
diff --git a/core/fpdfapi/font/cpdf_cidfont.cpp b/core/fpdfapi/font/cpdf_cidfont.cpp index 0c02b9e..6e0e665 100644 --- a/core/fpdfapi/font/cpdf_cidfont.cpp +++ b/core/fpdfapi/font/cpdf_cidfont.cpp
@@ -1,4 +1,4 @@ -// Copyright 2016 PDFium Authors. All rights reserved. +// Copyright 2016 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -8,6 +8,7 @@ #include <algorithm> #include <limits> +#include <utility> #include <vector> #include "build/build_config.h" @@ -20,18 +21,30 @@ #include "core/fpdfapi/font/cpdf_fontglobals.h" #include "core/fpdfapi/parser/cpdf_array.h" #include "core/fpdfapi/parser/cpdf_dictionary.h" +#include "core/fpdfapi/parser/cpdf_stream.h" #include "core/fpdfapi/parser/cpdf_stream_acc.h" +#include "core/fxcrt/fx_codepage.h" +#include "core/fxcrt/fx_memory.h" +#include "core/fxcrt/fx_safe_types.h" +#include "core/fxcrt/fx_unicode.h" +#include "core/fxcrt/stl_util.h" #include "core/fxge/fx_font.h" -#include "third_party/base/numerics/safe_math.h" -#include "third_party/base/ptr_util.h" +#include "third_party/base/check.h" +#include "third_party/base/check_op.h" +#include "third_party/base/cxx17_backports.h" #include "third_party/base/span.h" -#include "third_party/base/stl_util.h" namespace { -const uint16_t g_CharsetCPs[CIDSET_NUM_SETS] = {0, 936, 950, 932, 949, 1200}; +constexpr FX_CodePage kCharsetCodePages[CIDSET_NUM_SETS] = { + FX_CodePage::kDefANSI, + FX_CodePage::kChineseSimplified, + FX_CodePage::kChineseTraditional, + FX_CodePage::kShiftJIS, + FX_CodePage::kHangul, + FX_CodePage::kUTF16LE}; -const struct CIDTransform { +struct CIDTransform { uint16_t cid; uint8_t a; uint8_t b; @@ -39,7 +52,9 @@ uint8_t d; uint8_t e; uint8_t f; -} g_Japan1_VertCIDs[] = { +}; + +constexpr CIDTransform kJapan1VerticalCIDs[] = { {97, 129, 0, 0, 127, 55, 0}, {7887, 127, 0, 0, 127, 76, 89}, {7888, 127, 0, 0, 127, 79, 94}, {7889, 0, 129, 127, 0, 17, 127}, {7890, 0, 129, 127, 0, 17, 127}, {7891, 0, 129, 127, 0, 17, 127}, @@ -119,14 +134,17 @@ {8818, 0, 129, 127, 0, 19, 114}, {8819, 0, 129, 127, 0, 218, 108}, }; -// Boundary values to avoid integer overflow when multiplied by 1000. -constexpr long kMinCBox = -2147483; -constexpr long kMaxCBox = 2147483; - // Boundary value to avoid integer overflow when adding 1/64th of the value. constexpr int kMaxRectTop = 2114445437; -#if !defined(OS_WIN) +int FTPosToCBoxInt(FT_Pos pos) { + // Boundary values to avoid integer overflow when multiplied by 1000. + constexpr FT_Pos kMinCBox = -2147483; + constexpr FT_Pos kMaxCBox = 2147483; + return static_cast<int>(pdfium::clamp(pos, kMinCBox, kMaxCBox)); +} + +#if !BUILDFLAG(IS_WIN) bool IsValidEmbeddedCharcodeFromUnicodeCharset(CIDSet charset) { switch (charset) { @@ -141,13 +159,13 @@ } } -wchar_t EmbeddedUnicodeFromCharcode(const FXCMAP_CMap* pEmbedMap, +wchar_t EmbeddedUnicodeFromCharcode(const fxcmap::CMap* pEmbedMap, CIDSet charset, uint32_t charcode) { if (!IsValidEmbeddedCharcodeFromUnicodeCharset(charset)) return 0; - uint16_t cid = CIDFromCharCode(pEmbedMap, charcode); + uint16_t cid = fxcmap::CIDFromCharCode(pEmbedMap, charcode); if (!cid) return 0; @@ -156,7 +174,7 @@ return cid < map.size() ? map[cid] : 0; } -uint32_t EmbeddedCharcodeFromUnicode(const FXCMAP_CMap* pEmbedMap, +uint32_t EmbeddedCharcodeFromUnicode(const fxcmap::CMap* pEmbedMap, CIDSet charset, wchar_t unicode) { if (!IsValidEmbeddedCharcodeFromUnicodeCharset(charset)) @@ -166,7 +184,7 @@ CPDF_FontGlobals::GetInstance()->GetEmbeddedToUnicode(charset); for (uint32_t i = 0; i < map.size(); ++i) { if (map[i] == unicode) { - uint32_t charCode = CharCodeFromCID(pEmbedMap, i); + uint32_t charCode = fxcmap::CharCodeFromCID(pEmbedMap, i); if (charCode) return charCode; } @@ -174,21 +192,21 @@ return 0; } -#endif // !defined(OS_WIN) +#endif // !BUILDFLAG(IS_WIN) -void FT_UseCIDCharmap(FXFT_FaceRec* face, int coding) { +void FT_UseCIDCharmap(FXFT_FaceRec* face, CIDCoding coding) { int encoding; switch (coding) { - case CIDCODING_GB: + case CIDCoding::kGB: encoding = FT_ENCODING_GB2312; break; - case CIDCODING_BIG5: + case CIDCoding::kBIG5: encoding = FT_ENCODING_BIG5; break; - case CIDCODING_JIS: + case CIDCoding::kJIS: encoding = FT_ENCODING_SJIS; break; - case CIDCODING_KOREA: + case CIDCoding::kKOREA: encoding = FT_ENCODING_JOHAB; break; default: @@ -197,586 +215,32 @@ int err = FXFT_Select_Charmap(face, encoding); if (err) err = FXFT_Select_Charmap(face, FT_ENCODING_UNICODE); - if (err && FXFT_Get_Face_Charmaps(face)) - FT_Set_Charmap(face, *FXFT_Get_Face_Charmaps(face)); + if (err && face->charmaps) + FT_Set_Charmap(face, face->charmaps[0]); } -bool IsMetricForCID(const uint32_t* pEntry, uint16_t CID) { - return pEntry[0] <= CID && pEntry[1] >= CID; +bool IsMetricForCID(const int* pEntry, uint16_t cid) { + return pEntry[0] <= cid && pEntry[1] >= cid; } -} // namespace - -CPDF_CIDFont::CPDF_CIDFont(CPDF_Document* pDocument, CPDF_Dictionary* pFontDict) - : CPDF_Font(pDocument, pFontDict) { - for (size_t i = 0; i < FX_ArraySize(m_CharBBox); ++i) - m_CharBBox[i] = FX_RECT(-1, -1, -1, -1); -} - -CPDF_CIDFont::~CPDF_CIDFont() {} - -bool CPDF_CIDFont::IsCIDFont() const { - return true; -} - -const CPDF_CIDFont* CPDF_CIDFont::AsCIDFont() const { - return this; -} - -CPDF_CIDFont* CPDF_CIDFont::AsCIDFont() { - return this; -} - -uint16_t CPDF_CIDFont::CIDFromCharCode(uint32_t charcode) const { - return m_pCMap ? m_pCMap->CIDFromCharCode(charcode) - : static_cast<uint16_t>(charcode); -} - -bool CPDF_CIDFont::IsVertWriting() const { - return m_pCMap && m_pCMap->IsVertWriting(); -} - -WideString CPDF_CIDFont::UnicodeFromCharCode(uint32_t charcode) const { - WideString str = CPDF_Font::UnicodeFromCharCode(charcode); - if (!str.IsEmpty()) - return str; - wchar_t ret = GetUnicodeFromCharCode(charcode); - return ret ? ret : WideString(); -} - -wchar_t CPDF_CIDFont::GetUnicodeFromCharCode(uint32_t charcode) const { - switch (m_pCMap->GetCoding()) { - case CIDCODING_UCS2: - case CIDCODING_UTF16: - return static_cast<wchar_t>(charcode); - case CIDCODING_CID: - if (!m_pCID2UnicodeMap || !m_pCID2UnicodeMap->IsLoaded()) - return 0; - return m_pCID2UnicodeMap->UnicodeFromCID(static_cast<uint16_t>(charcode)); - } - if (m_pCID2UnicodeMap && m_pCID2UnicodeMap->IsLoaded() && m_pCMap->IsLoaded()) - return m_pCID2UnicodeMap->UnicodeFromCID(CIDFromCharCode(charcode)); - -#if defined(OS_WIN) - wchar_t unicode; - int charsize = 1; - if (charcode > 255) { - charcode = (charcode % 256) * 256 + (charcode / 256); - charsize = 2; - } - int ret = FXSYS_MultiByteToWideChar(g_CharsetCPs[m_pCMap->GetCoding()], 0, - reinterpret_cast<const char*>(&charcode), - charsize, &unicode, 1); - return ret == 1 ? unicode : 0; -#else - if (!m_pCMap->GetEmbedMap()) - return 0; - return EmbeddedUnicodeFromCharcode(m_pCMap->GetEmbedMap(), - m_pCMap->GetCharset(), charcode); -#endif -} - -uint32_t CPDF_CIDFont::CharCodeFromUnicode(wchar_t unicode) const { - uint32_t charcode = CPDF_Font::CharCodeFromUnicode(unicode); - if (charcode) - return charcode; - switch (m_pCMap->GetCoding()) { - case CIDCODING_UNKNOWN: - return 0; - case CIDCODING_UCS2: - case CIDCODING_UTF16: - return unicode; - case CIDCODING_CID: { - if (!m_pCID2UnicodeMap || !m_pCID2UnicodeMap->IsLoaded()) - return 0; - uint32_t CID = 0; - while (CID < 65536) { - wchar_t this_unicode = - m_pCID2UnicodeMap->UnicodeFromCID(static_cast<uint16_t>(CID)); - if (this_unicode == unicode) - return CID; - CID++; - } - break; - } - } - - if (unicode < 0x80) - return static_cast<uint32_t>(unicode); - if (m_pCMap->GetCoding() == CIDCODING_CID) - return 0; -#if defined(OS_WIN) - uint8_t buffer[32]; - int ret = FXSYS_WideCharToMultiByte( - g_CharsetCPs[m_pCMap->GetCoding()], 0, &unicode, 1, - reinterpret_cast<char*>(buffer), 4, nullptr, nullptr); - if (ret == 1) - return buffer[0]; - if (ret == 2) - return buffer[0] * 256 + buffer[1]; -#else - if (m_pCMap->GetEmbedMap()) { - return EmbeddedCharcodeFromUnicode(m_pCMap->GetEmbedMap(), - m_pCMap->GetCharset(), unicode); - } -#endif - return 0; -} - -bool CPDF_CIDFont::Load() { - if (m_pFontDict->GetStringFor("Subtype") == "TrueType") { - LoadGB2312(); - return true; - } - - const CPDF_Array* pFonts = m_pFontDict->GetArrayFor("DescendantFonts"); - if (!pFonts || pFonts->size() != 1) - return false; - - const CPDF_Dictionary* pCIDFontDict = pFonts->GetDictAt(0); - if (!pCIDFontDict) - return false; - - m_BaseFontName = pCIDFontDict->GetStringFor("BaseFont"); - if ((m_BaseFontName.Compare("CourierStd") == 0 || - m_BaseFontName.Compare("CourierStd-Bold") == 0 || - m_BaseFontName.Compare("CourierStd-BoldOblique") == 0 || - m_BaseFontName.Compare("CourierStd-Oblique") == 0) && - !IsEmbedded()) { - m_bAdobeCourierStd = true; - } - - CPDF_Object* pEncoding = m_pFontDict->GetDirectObjectFor("Encoding"); - if (!pEncoding) - return false; - - ByteString subtype = pCIDFontDict->GetStringFor("Subtype"); - m_bType1 = (subtype == "CIDFontType0"); - - CPDF_CMapManager* manager = CPDF_FontGlobals::GetInstance()->GetCMapManager(); - if (pEncoding->IsName()) { - ByteString cmap = pEncoding->GetString(); - m_pCMap = manager->GetPredefinedCMap(cmap); - } else if (CPDF_Stream* pStream = pEncoding->AsStream()) { - auto pAcc = pdfium::MakeRetain<CPDF_StreamAcc>(pStream); - pAcc->LoadAllDataFiltered(); - pdfium::span<const uint8_t> span = pAcc->GetSpan(); - m_pCMap = pdfium::MakeRetain<CPDF_CMap>(span); - } else { - return false; - } - - const CPDF_Dictionary* pFontDesc = pCIDFontDict->GetDictFor("FontDescriptor"); - if (pFontDesc) - LoadFontDescriptor(pFontDesc); - - m_Charset = m_pCMap->GetCharset(); - if (m_Charset == CIDSET_UNKNOWN) { - const CPDF_Dictionary* pCIDInfo = pCIDFontDict->GetDictFor("CIDSystemInfo"); - if (pCIDInfo) { - m_Charset = CPDF_CMapParser::CharsetFromOrdering( - pCIDInfo->GetStringFor("Ordering").AsStringView()); - } - } - if (m_Charset != CIDSET_UNKNOWN) { - m_pCID2UnicodeMap = manager->GetCID2UnicodeMap(m_Charset); - } - if (m_Font.GetFaceRec()) { - if (m_bType1) - FXFT_Select_Charmap(m_Font.GetFaceRec(), FT_ENCODING_UNICODE); - else - FT_UseCIDCharmap(m_Font.GetFaceRec(), m_pCMap->GetCoding()); - } - m_DefaultWidth = pCIDFontDict->GetIntegerFor("DW", 1000); - const CPDF_Array* pWidthArray = pCIDFontDict->GetArrayFor("W"); - if (pWidthArray) - LoadMetricsArray(pWidthArray, &m_WidthList, 1); - if (!IsEmbedded()) - LoadSubstFont(); - - const CPDF_Object* pmap = pCIDFontDict->GetDirectObjectFor("CIDToGIDMap"); - if (pmap) { - if (const CPDF_Stream* pStream = pmap->AsStream()) { - m_pStreamAcc = pdfium::MakeRetain<CPDF_StreamAcc>(pStream); - m_pStreamAcc->LoadAllDataFiltered(); - } else if (m_pFontFile && pmap->GetString() == "Identity") { - m_bCIDIsGID = true; - } - } - - CheckFontMetrics(); - if (IsVertWriting()) { - pWidthArray = pCIDFontDict->GetArrayFor("W2"); - if (pWidthArray) - LoadMetricsArray(pWidthArray, &m_VertMetrics, 3); - const CPDF_Array* pDefaultArray = pCIDFontDict->GetArrayFor("DW2"); - if (pDefaultArray) { - m_DefaultVY = pDefaultArray->GetIntegerAt(0); - m_DefaultW1 = pDefaultArray->GetIntegerAt(1); - } - } - return true; -} - -FX_RECT CPDF_CIDFont::GetCharBBox(uint32_t charcode) { - if (charcode < 256 && m_CharBBox[charcode].right != -1) - return m_CharBBox[charcode]; - - FX_RECT rect; - bool bVert = false; - int glyph_index = GlyphFromCharCode(charcode, &bVert); - FXFT_FaceRec* face = m_Font.GetFaceRec(); - if (face) { - if (FXFT_Is_Face_Tricky(face)) { - int err = - FT_Load_Glyph(face, glyph_index, FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH); - if (!err) { - FT_Glyph glyph; - err = FT_Get_Glyph(face->glyph, &glyph); - if (!err) { - FT_BBox cbox; - FT_Glyph_Get_CBox(glyph, FT_GLYPH_BBOX_PIXELS, &cbox); - cbox.xMin = pdfium::clamp(cbox.xMin, kMinCBox, kMaxCBox); - cbox.xMax = pdfium::clamp(cbox.xMax, kMinCBox, kMaxCBox); - cbox.yMin = pdfium::clamp(cbox.yMin, kMinCBox, kMaxCBox); - cbox.yMax = pdfium::clamp(cbox.yMax, kMinCBox, kMaxCBox); - int pixel_size_x = face->size->metrics.x_ppem; - int pixel_size_y = face->size->metrics.y_ppem; - if (pixel_size_x == 0 || pixel_size_y == 0) { - rect = FX_RECT(cbox.xMin, cbox.yMax, cbox.xMax, cbox.yMin); - } else { - rect = FX_RECT(cbox.xMin * 1000 / pixel_size_x, - cbox.yMax * 1000 / pixel_size_y, - cbox.xMax * 1000 / pixel_size_x, - cbox.yMin * 1000 / pixel_size_y); - } - rect.top = std::min(rect.top, - static_cast<int>(FXFT_Get_Face_Ascender(face))); - rect.bottom = std::max( - rect.bottom, static_cast<int>(FXFT_Get_Face_Descender(face))); - FT_Done_Glyph(glyph); - } - } - } else { - int err = FT_Load_Glyph(face, glyph_index, FT_LOAD_NO_SCALE); - if (err == 0) { - rect = FX_RECT(TT2PDF(FXFT_Get_Glyph_HoriBearingX(face), face), - TT2PDF(FXFT_Get_Glyph_HoriBearingY(face), face), - TT2PDF(FXFT_Get_Glyph_HoriBearingX(face) + - FXFT_Get_Glyph_Width(face), - face), - TT2PDF(FXFT_Get_Glyph_HoriBearingY(face) - - FXFT_Get_Glyph_Height(face), - face)); - if (rect.top <= kMaxRectTop) - rect.top += rect.top / 64; - else - rect.top = std::numeric_limits<int>::max(); - } - } - } - if (!m_pFontFile && m_Charset == CIDSET_JAPAN1) { - uint16_t CID = CIDFromCharCode(charcode); - const uint8_t* pTransform = GetCIDTransform(CID); - if (pTransform && !bVert) { - CFX_Matrix matrix(CIDTransformToFloat(pTransform[0]), - CIDTransformToFloat(pTransform[1]), - CIDTransformToFloat(pTransform[2]), - CIDTransformToFloat(pTransform[3]), - CIDTransformToFloat(pTransform[4]) * 1000, - CIDTransformToFloat(pTransform[5]) * 1000); - rect = matrix.TransformRect(CFX_FloatRect(rect)).GetOuterRect(); - } - } - if (charcode < 256) - m_CharBBox[charcode] = rect; - - return rect; -} - -uint32_t CPDF_CIDFont::GetCharWidthF(uint32_t charcode) { - if (charcode < 0x80 && m_bAnsiWidthsFixed) - return (charcode >= 32 && charcode < 127) ? 500 : 0; - - uint16_t cid = CIDFromCharCode(charcode); - size_t size = m_WidthList.size(); - const uint32_t* pList = m_WidthList.data(); - for (size_t i = 0; i < size; i += 3) { - const uint32_t* pEntry = pList + i; - if (IsMetricForCID(pEntry, cid)) - return pEntry[2]; - } - return m_DefaultWidth; -} - -short CPDF_CIDFont::GetVertWidth(uint16_t CID) const { - size_t vertsize = m_VertMetrics.size() / 5; - if (vertsize) { - const uint32_t* pTable = m_VertMetrics.data(); - for (size_t i = 0; i < vertsize; i++) { - const uint32_t* pEntry = pTable + (i * 5); - if (IsMetricForCID(pEntry, CID)) - return static_cast<short>(pEntry[2]); - } - } - return m_DefaultW1; -} - -void CPDF_CIDFont::GetVertOrigin(uint16_t CID, short& vx, short& vy) const { - size_t vertsize = m_VertMetrics.size() / 5; - if (vertsize) { - const uint32_t* pTable = m_VertMetrics.data(); - for (size_t i = 0; i < vertsize; i++) { - const uint32_t* pEntry = pTable + (i * 5); - if (IsMetricForCID(pEntry, CID)) { - vx = static_cast<short>(pEntry[3]); - vy = static_cast<short>(pEntry[4]); - return; - } - } - } - uint32_t dwWidth = m_DefaultWidth; - size_t size = m_WidthList.size(); - const uint32_t* pList = m_WidthList.data(); - for (size_t i = 0; i < size; i += 3) { - const uint32_t* pEntry = pList + i; - if (IsMetricForCID(pEntry, CID)) { - dwWidth = pEntry[2]; - break; - } - } - vx = static_cast<short>(dwWidth) / 2; - vy = m_DefaultVY; -} - -int CPDF_CIDFont::GetGlyphIndex(uint32_t unicode, bool* pVertGlyph) { - if (pVertGlyph) - *pVertGlyph = false; - - FXFT_FaceRec* face = m_Font.GetFaceRec(); - int index = FT_Get_Char_Index(face, unicode); - if (unicode == 0x2502) - return index; - - if (!index || !IsVertWriting()) - return index; - - if (m_pTTGSUBTable) - return GetVerticalGlyph(index, pVertGlyph); - - if (!m_Font.GetSubData()) { - unsigned long length = 0; - int error = FT_Load_Sfnt_Table(face, FT_MAKE_TAG('G', 'S', 'U', 'B'), 0, - nullptr, &length); - if (!error) - m_Font.SetSubData(FX_Alloc(uint8_t, length)); - } - int error = FT_Load_Sfnt_Table(face, FT_MAKE_TAG('G', 'S', 'U', 'B'), 0, - m_Font.GetSubData(), nullptr); - if (error || !m_Font.GetSubData()) - return index; - - m_pTTGSUBTable = pdfium::MakeUnique<CFX_CTTGSUBTable>(m_Font.GetSubData()); - return GetVerticalGlyph(index, pVertGlyph); -} - -int CPDF_CIDFont::GetVerticalGlyph(int index, bool* pVertGlyph) { - uint32_t vindex = m_pTTGSUBTable->GetVerticalGlyph(index); - if (!vindex) - return index; - - index = vindex; - if (pVertGlyph) - *pVertGlyph = true; - return index; -} - -int CPDF_CIDFont::GlyphFromCharCode(uint32_t charcode, bool* pVertGlyph) { - if (pVertGlyph) - *pVertGlyph = false; - - if (!m_pFontFile && (!m_pStreamAcc || m_pCID2UnicodeMap)) { - uint16_t cid = CIDFromCharCode(charcode); - wchar_t unicode = 0; - if (m_bCIDIsGID) { -#if defined(OS_MACOSX) - if (FontStyleIsSymbolic(m_Flags)) - return cid; - - WideString uni_str = UnicodeFromCharCode(charcode); - if (uni_str.IsEmpty()) - return cid; - - unicode = uni_str[0]; -#else - return cid; -#endif - } else { - if (cid && m_pCID2UnicodeMap && m_pCID2UnicodeMap->IsLoaded()) - unicode = m_pCID2UnicodeMap->UnicodeFromCID(cid); - if (unicode == 0) - unicode = GetUnicodeFromCharCode(charcode); - if (unicode == 0) { - WideString unicode_str = UnicodeFromCharCode(charcode); - if (!unicode_str.IsEmpty()) - unicode = unicode_str[0]; - } - } - FXFT_FaceRec* face = m_Font.GetFaceRec(); - if (unicode == 0) { - if (!m_bAdobeCourierStd) - return charcode ? static_cast<int>(charcode) : -1; - - charcode += 31; - bool bMSUnicode = FT_UseTTCharmap(face, 3, 1); - bool bMacRoman = !bMSUnicode && FT_UseTTCharmap(face, 1, 0); - int iBaseEncoding = PDFFONT_ENCODING_STANDARD; - if (bMSUnicode) - iBaseEncoding = PDFFONT_ENCODING_WINANSI; - else if (bMacRoman) - iBaseEncoding = PDFFONT_ENCODING_MACROMAN; - const char* name = - GetAdobeCharName(iBaseEncoding, std::vector<ByteString>(), charcode); - if (!name) - return charcode ? static_cast<int>(charcode) : -1; - - int index = 0; - uint16_t name_unicode = PDF_UnicodeFromAdobeName(name); - if (!name_unicode) - return charcode ? static_cast<int>(charcode) : -1; - - if (iBaseEncoding == PDFFONT_ENCODING_STANDARD) - return FT_Get_Char_Index(face, name_unicode); - - if (iBaseEncoding == PDFFONT_ENCODING_WINANSI) { - index = FT_Get_Char_Index(face, name_unicode); - } else { - ASSERT(iBaseEncoding == PDFFONT_ENCODING_MACROMAN); - uint32_t maccode = - FT_CharCodeFromUnicode(FT_ENCODING_APPLE_ROMAN, name_unicode); - index = maccode ? FT_Get_Char_Index(face, maccode) - : FXFT_Get_Name_Index(face, name); - } - if (index == 0 || index == 0xffff) - return charcode ? static_cast<int>(charcode) : -1; - return index; - } - if (m_Charset == CIDSET_JAPAN1) { - if (unicode == '\\') { - unicode = '/'; -#if !defined(OS_MACOSX) - } else if (unicode == 0xa5) { - unicode = 0x5c; -#endif - } - } - if (!face) - return unicode; - - int err = FXFT_Select_Charmap(face, FT_ENCODING_UNICODE); - if (err) { - int i; - for (i = 0; i < FXFT_Get_Face_CharmapCount(face); i++) { - uint32_t ret = FT_CharCodeFromUnicode( - FXFT_Get_Charmap_Encoding(FXFT_Get_Face_Charmaps(face)[i]), - static_cast<wchar_t>(charcode)); - if (ret == 0) - continue; - FT_Set_Charmap(face, FXFT_Get_Face_Charmaps(face)[i]); - unicode = static_cast<wchar_t>(ret); - break; - } - if (i == FXFT_Get_Face_CharmapCount(face) && i) { - FT_Set_Charmap(face, FXFT_Get_Face_Charmaps(face)[0]); - unicode = static_cast<wchar_t>(charcode); - } - } - if (FXFT_Get_Face_Charmap(face)) { - int index = GetGlyphIndex(unicode, pVertGlyph); - return index != 0 ? index : -1; - } - return unicode; - } - - if (!m_Font.GetFaceRec()) - return -1; - - uint16_t cid = CIDFromCharCode(charcode); - if (!m_pStreamAcc) { - if (m_bType1) - return cid; - if (m_pFontFile && m_pCMap->IsDirectCharcodeToCIDTableIsEmpty()) - return cid; - if (m_pCMap->GetCoding() == CIDCODING_UNKNOWN || - !FXFT_Get_Face_Charmap(m_Font.GetFaceRec())) { - return cid; - } - if (FXFT_Get_Charmap_Encoding(FXFT_Get_Face_Charmap(m_Font.GetFaceRec())) == - FT_ENCODING_UNICODE) { - WideString unicode_str = UnicodeFromCharCode(charcode); - if (unicode_str.IsEmpty()) - return -1; - - charcode = unicode_str[0]; - } - return GetGlyphIndex(charcode, pVertGlyph); - } - uint32_t byte_pos = cid * 2; - if (byte_pos + 2 > m_pStreamAcc->GetSize()) - return -1; - - const uint8_t* pdata = m_pStreamAcc->GetData() + byte_pos; - return pdata[0] * 256 + pdata[1]; -} - -uint32_t CPDF_CIDFont::GetNextChar(ByteStringView pString, - size_t* pOffset) const { - return m_pCMap->GetNextChar(pString, pOffset); -} - -int CPDF_CIDFont::GetCharSize(uint32_t charcode) const { - return m_pCMap->GetCharSize(charcode); -} - -size_t CPDF_CIDFont::CountChar(ByteStringView pString) const { - return m_pCMap->CountChar(pString); -} - -int CPDF_CIDFont::AppendChar(char* str, uint32_t charcode) const { - return m_pCMap->AppendChar(str, charcode); -} - -bool CPDF_CIDFont::IsUnicodeCompatible() const { - if (m_pCID2UnicodeMap && m_pCID2UnicodeMap->IsLoaded() && m_pCMap->IsLoaded()) - return true; - return m_pCMap->GetCoding() != CIDCODING_UNKNOWN; -} - -void CPDF_CIDFont::LoadSubstFont() { - pdfium::base::CheckedNumeric<int> safeStemV(m_StemV); - safeStemV *= 5; - m_Font.LoadSubst(m_BaseFontName, !m_bType1, m_Flags, - safeStemV.ValueOrDefault(FXFONT_FW_NORMAL), m_ItalicAngle, - g_CharsetCPs[m_Charset], IsVertWriting()); -} - -void CPDF_CIDFont::LoadMetricsArray(const CPDF_Array* pArray, - std::vector<uint32_t>* result, - int nElements) { +void LoadMetricsArray(RetainPtr<const CPDF_Array> pArray, + std::vector<int>* result, + int nElements) { int width_status = 0; int iCurElement = 0; - uint32_t first_code = 0; - uint32_t last_code = 0; + int first_code = 0; + int last_code = 0; for (size_t i = 0; i < pArray->size(); i++) { - const CPDF_Object* pObj = pArray->GetDirectObjectAt(i); + RetainPtr<const CPDF_Object> pObj = pArray->GetDirectObjectAt(i); if (!pObj) continue; - if (const CPDF_Array* pObjArray = pObj->AsArray()) { + const CPDF_Array* pObjArray = pObj->AsArray(); + if (pObjArray) { if (width_status != 1) return; - if (first_code > - std::numeric_limits<uint32_t>::max() - pObjArray->size()) { + if (first_code > std::numeric_limits<int>::max() - + fxcrt::CollectionSize<int>(*pObjArray)) { width_status = 0; continue; } @@ -811,21 +275,603 @@ } } +} // namespace + +CPDF_CIDFont::CPDF_CIDFont(CPDF_Document* pDocument, + RetainPtr<CPDF_Dictionary> pFontDict) + : CPDF_Font(pDocument, std::move(pFontDict)) { + for (size_t i = 0; i < std::size(m_CharBBox); ++i) + m_CharBBox[i] = FX_RECT(-1, -1, -1, -1); +} + +CPDF_CIDFont::~CPDF_CIDFont() = default; + +bool CPDF_CIDFont::IsCIDFont() const { + return true; +} + +const CPDF_CIDFont* CPDF_CIDFont::AsCIDFont() const { + return this; +} + +CPDF_CIDFont* CPDF_CIDFont::AsCIDFont() { + return this; +} + +uint16_t CPDF_CIDFont::CIDFromCharCode(uint32_t charcode) const { + return m_pCMap ? m_pCMap->CIDFromCharCode(charcode) + : static_cast<uint16_t>(charcode); +} + +bool CPDF_CIDFont::IsVertWriting() const { + return m_pCMap && m_pCMap->IsVertWriting(); +} + +WideString CPDF_CIDFont::UnicodeFromCharCode(uint32_t charcode) const { + WideString str = CPDF_Font::UnicodeFromCharCode(charcode); + if (!str.IsEmpty()) + return str; + wchar_t ret = GetUnicodeFromCharCode(charcode); + return ret ? WideString(ret) : WideString(); +} + +wchar_t CPDF_CIDFont::GetUnicodeFromCharCode(uint32_t charcode) const { + switch (m_pCMap->GetCoding()) { + case CIDCoding::kUCS2: + case CIDCoding::kUTF16: + return static_cast<wchar_t>(charcode); + case CIDCoding::kCID: + if (!m_pCID2UnicodeMap || !m_pCID2UnicodeMap->IsLoaded()) + return 0; + return m_pCID2UnicodeMap->UnicodeFromCID(static_cast<uint16_t>(charcode)); + default: + break; + } + if (m_pCID2UnicodeMap && m_pCID2UnicodeMap->IsLoaded() && m_pCMap->IsLoaded()) + return m_pCID2UnicodeMap->UnicodeFromCID(CIDFromCharCode(charcode)); + +#if BUILDFLAG(IS_WIN) + wchar_t unicode; + int charsize = 1; + if (charcode > 255) { + charcode = (charcode % 256) * 256 + (charcode / 256); + charsize = 2; + } + size_t ret = FX_MultiByteToWideChar( + kCharsetCodePages[static_cast<size_t>(m_pCMap->GetCoding())], + ByteStringView(reinterpret_cast<const char*>(&charcode), charsize), + pdfium::make_span(&unicode, 1)); + return ret == 1 ? unicode : 0; +#else + if (!m_pCMap->GetEmbedMap()) + return 0; + return EmbeddedUnicodeFromCharcode(m_pCMap->GetEmbedMap(), + m_pCMap->GetCharset(), charcode); +#endif +} + +uint32_t CPDF_CIDFont::CharCodeFromUnicode(wchar_t unicode) const { + uint32_t charcode = CPDF_Font::CharCodeFromUnicode(unicode); + if (charcode) + return charcode; + + switch (m_pCMap->GetCoding()) { + case CIDCoding::kUNKNOWN: + return 0; + case CIDCoding::kUCS2: + case CIDCoding::kUTF16: + return unicode; + case CIDCoding::kCID: { + if (!m_pCID2UnicodeMap || !m_pCID2UnicodeMap->IsLoaded()) + return 0; + uint32_t cid = 0; + while (cid < 65536) { + wchar_t this_unicode = + m_pCID2UnicodeMap->UnicodeFromCID(static_cast<uint16_t>(cid)); + if (this_unicode == unicode) + return cid; + cid++; + } + break; + } + default: + break; + } + + if (unicode < 0x80) + return static_cast<uint32_t>(unicode); + if (m_pCMap->GetCoding() == CIDCoding::kCID) + return 0; +#if BUILDFLAG(IS_WIN) + uint8_t buffer[32]; + size_t ret = FX_WideCharToMultiByte( + kCharsetCodePages[static_cast<size_t>(m_pCMap->GetCoding())], + WideStringView(&unicode, 1), + pdfium::make_span(reinterpret_cast<char*>(buffer), 4)); + if (ret == 1) + return buffer[0]; + if (ret == 2) + return buffer[0] * 256 + buffer[1]; +#else + if (m_pCMap->GetEmbedMap()) { + return EmbeddedCharcodeFromUnicode(m_pCMap->GetEmbedMap(), + m_pCMap->GetCharset(), unicode); + } +#endif + return 0; +} + +bool CPDF_CIDFont::Load() { + if (m_pFontDict->GetByteStringFor("Subtype") == "TrueType") { + LoadGB2312(); + return true; + } + + RetainPtr<const CPDF_Array> pFonts = + m_pFontDict->GetArrayFor("DescendantFonts"); + if (!pFonts || pFonts->size() != 1) + return false; + + RetainPtr<const CPDF_Dictionary> pCIDFontDict = pFonts->GetDictAt(0); + if (!pCIDFontDict) + return false; + + m_BaseFontName = pCIDFontDict->GetByteStringFor("BaseFont"); + if ((m_BaseFontName == "CourierStd" || m_BaseFontName == "CourierStd-Bold" || + m_BaseFontName == "CourierStd-BoldOblique" || + m_BaseFontName == "CourierStd-Oblique") && + !IsEmbedded()) { + m_bAdobeCourierStd = true; + } + + RetainPtr<const CPDF_Object> pEncoding = + m_pFontDict->GetDirectObjectFor("Encoding"); + if (!pEncoding) + return false; + + ByteString subtype = pCIDFontDict->GetByteStringFor("Subtype"); + m_FontType = + subtype == "CIDFontType0" ? CIDFontType::kType1 : CIDFontType::kTrueType; + + if (!pEncoding->IsName() && !pEncoding->IsStream()) + return false; + + auto* pFontGlobals = CPDF_FontGlobals::GetInstance(); + const CPDF_Stream* pEncodingStream = pEncoding->AsStream(); + if (pEncodingStream) { + auto pAcc = + pdfium::MakeRetain<CPDF_StreamAcc>(pdfium::WrapRetain(pEncodingStream)); + pAcc->LoadAllDataFiltered(); + pdfium::span<const uint8_t> span = pAcc->GetSpan(); + m_pCMap = pdfium::MakeRetain<CPDF_CMap>(span); + } else { + DCHECK(pEncoding->IsName()); + ByteString cmap = pEncoding->GetString(); + m_pCMap = pFontGlobals->GetPredefinedCMap(cmap); + } + + RetainPtr<const CPDF_Dictionary> pFontDesc = + pCIDFontDict->GetDictFor("FontDescriptor"); + if (pFontDesc) + LoadFontDescriptor(pFontDesc.Get()); + + m_Charset = m_pCMap->GetCharset(); + if (m_Charset == CIDSET_UNKNOWN) { + RetainPtr<const CPDF_Dictionary> pCIDInfo = + pCIDFontDict->GetDictFor("CIDSystemInfo"); + if (pCIDInfo) { + m_Charset = CPDF_CMapParser::CharsetFromOrdering( + pCIDInfo->GetByteStringFor("Ordering").AsStringView()); + } + } + if (m_Charset != CIDSET_UNKNOWN) { + m_pCID2UnicodeMap = pFontGlobals->GetCID2UnicodeMap(m_Charset); + } + if (m_Font.GetFaceRec()) { + if (m_FontType == CIDFontType::kType1) + FXFT_Select_Charmap(m_Font.GetFaceRec(), FT_ENCODING_UNICODE); + else + FT_UseCIDCharmap(m_Font.GetFaceRec(), m_pCMap->GetCoding()); + } + m_DefaultWidth = pCIDFontDict->GetIntegerFor("DW", 1000); + RetainPtr<const CPDF_Array> pWidthArray = pCIDFontDict->GetArrayFor("W"); + if (pWidthArray) + LoadMetricsArray(std::move(pWidthArray), &m_WidthList, 1); + + if (!IsEmbedded()) + LoadSubstFont(); + + RetainPtr<const CPDF_Object> pmap = + pCIDFontDict->GetDirectObjectFor("CIDToGIDMap"); + if (pmap) { + RetainPtr<const CPDF_Stream> pMapStream(pmap->AsStream()); + if (pMapStream) { + m_pStreamAcc = pdfium::MakeRetain<CPDF_StreamAcc>(std::move(pMapStream)); + m_pStreamAcc->LoadAllDataFiltered(); + } else if (m_pFontFile && pmap->IsName() && + pmap->GetString() == "Identity") { + m_bCIDIsGID = true; + } + } + + CheckFontMetrics(); + if (IsVertWriting()) { + RetainPtr<const CPDF_Array> pWidth2Array = pCIDFontDict->GetArrayFor("W2"); + if (pWidth2Array) + LoadMetricsArray(std::move(pWidth2Array), &m_VertMetrics, 3); + + RetainPtr<const CPDF_Array> pDefaultArray = + pCIDFontDict->GetArrayFor("DW2"); + if (pDefaultArray) { + m_DefaultVY = pDefaultArray->GetIntegerAt(0); + m_DefaultW1 = pDefaultArray->GetIntegerAt(1); + } + } + + // TODO(thestig): Better identify font types and identify more font types. + if (m_FontType == CIDFontType::kTrueType && IsEmbedded()) + m_Font.SetFontType(CFX_Font::FontType::kCIDTrueType); + + return true; +} + +FX_RECT CPDF_CIDFont::GetCharBBox(uint32_t charcode) { + if (charcode < 256 && m_CharBBox[charcode].right != -1) + return m_CharBBox[charcode]; + + FX_RECT rect; + bool bVert = false; + int glyph_index = GlyphFromCharCode(charcode, &bVert); + FXFT_FaceRec* face = m_Font.GetFaceRec(); + if (face) { + if (FXFT_Is_Face_Tricky(face)) { + int err = + FT_Load_Glyph(face, glyph_index, FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH); + if (!err) { + FT_Glyph glyph; + err = FT_Get_Glyph(face->glyph, &glyph); + if (!err) { + FT_BBox cbox; + FT_Glyph_Get_CBox(glyph, FT_GLYPH_BBOX_PIXELS, &cbox); + const int xMin = FTPosToCBoxInt(cbox.xMin); + const int xMax = FTPosToCBoxInt(cbox.xMax); + const int yMin = FTPosToCBoxInt(cbox.yMin); + const int yMax = FTPosToCBoxInt(cbox.yMax); + const int pixel_size_x = face->size->metrics.x_ppem; + const int pixel_size_y = face->size->metrics.y_ppem; + if (pixel_size_x == 0 || pixel_size_y == 0) { + rect = FX_RECT(xMin, yMax, xMax, yMin); + } else { + rect = + FX_RECT(xMin * 1000 / pixel_size_x, yMax * 1000 / pixel_size_y, + xMax * 1000 / pixel_size_x, yMin * 1000 / pixel_size_y); + } + rect.top = std::min(rect.top, + static_cast<int>(FXFT_Get_Face_Ascender(face))); + rect.bottom = std::max( + rect.bottom, static_cast<int>(FXFT_Get_Face_Descender(face))); + FT_Done_Glyph(glyph); + } + } + } else { + int err = FT_Load_Glyph(face, glyph_index, FT_LOAD_NO_SCALE); + if (err == 0) { + rect = FX_RECT(TT2PDF(FXFT_Get_Glyph_HoriBearingX(face), face), + TT2PDF(FXFT_Get_Glyph_HoriBearingY(face), face), + TT2PDF(FXFT_Get_Glyph_HoriBearingX(face) + + FXFT_Get_Glyph_Width(face), + face), + TT2PDF(FXFT_Get_Glyph_HoriBearingY(face) - + FXFT_Get_Glyph_Height(face), + face)); + if (rect.top <= kMaxRectTop) + rect.top += rect.top / 64; + else + rect.top = std::numeric_limits<int>::max(); + } + } + } + if (!m_pFontFile && m_Charset == CIDSET_JAPAN1) { + uint16_t cid = CIDFromCharCode(charcode); + const uint8_t* pTransform = GetCIDTransform(cid); + if (pTransform && !bVert) { + CFX_Matrix matrix(CIDTransformToFloat(pTransform[0]), + CIDTransformToFloat(pTransform[1]), + CIDTransformToFloat(pTransform[2]), + CIDTransformToFloat(pTransform[3]), + CIDTransformToFloat(pTransform[4]) * 1000, + CIDTransformToFloat(pTransform[5]) * 1000); + rect = matrix.TransformRect(CFX_FloatRect(rect)).GetOuterRect(); + } + } + if (charcode < 256) + m_CharBBox[charcode] = rect; + + return rect; +} + +int CPDF_CIDFont::GetCharWidthF(uint32_t charcode) { + if (charcode < 0x80 && m_bAnsiWidthsFixed) + return (charcode >= 32 && charcode < 127) ? 500 : 0; + + uint16_t cid = CIDFromCharCode(charcode); + size_t size = m_WidthList.size(); + const int* pList = m_WidthList.data(); + for (size_t i = 0; i < size; i += 3) { + const int* pEntry = pList + i; + if (IsMetricForCID(pEntry, cid)) + return pEntry[2]; + } + return m_DefaultWidth; +} + +int16_t CPDF_CIDFont::GetVertWidth(uint16_t cid) const { + size_t vertsize = m_VertMetrics.size() / 5; + if (vertsize) { + const int* pTable = m_VertMetrics.data(); + for (size_t i = 0; i < vertsize; i++) { + const int* pEntry = pTable + (i * 5); + if (IsMetricForCID(pEntry, cid)) + return static_cast<int16_t>(pEntry[2]); + } + } + return m_DefaultW1; +} + +CFX_Point16 CPDF_CIDFont::GetVertOrigin(uint16_t cid) const { + size_t vertsize = m_VertMetrics.size() / 5; + if (vertsize) { + const int* pTable = m_VertMetrics.data(); + for (size_t i = 0; i < vertsize; i++) { + const int* pEntry = pTable + (i * 5); + if (IsMetricForCID(pEntry, cid)) { + return {static_cast<int16_t>(pEntry[3]), + static_cast<int16_t>(pEntry[4])}; + } + } + } + int width = m_DefaultWidth; + size_t size = m_WidthList.size(); + const int* pList = m_WidthList.data(); + for (size_t i = 0; i < size; i += 3) { + const int* pEntry = pList + i; + if (IsMetricForCID(pEntry, cid)) { + width = pEntry[2]; + break; + } + } + return {static_cast<int16_t>(width / 2), m_DefaultVY}; +} + +int CPDF_CIDFont::GetGlyphIndex(uint32_t unicode, bool* pVertGlyph) { + if (pVertGlyph) + *pVertGlyph = false; + + FXFT_FaceRec* face = m_Font.GetFaceRec(); + int index = FT_Get_Char_Index(face, unicode); + if (unicode == pdfium::unicode::kBoxDrawingsLightVerical) + return index; + + if (!index || !IsVertWriting()) + return index; + + if (m_pTTGSUBTable) + return GetVerticalGlyph(index, pVertGlyph); + + static constexpr uint32_t kGsubTag = + CFX_FontMapper::MakeTag('G', 'S', 'U', 'B'); + if (!m_Font.GetSubData()) { + unsigned long length = 0; + int error = FT_Load_Sfnt_Table(face, kGsubTag, 0, nullptr, &length); + if (!error) + m_Font.AllocSubData(length); + } + int error = + FT_Load_Sfnt_Table(face, kGsubTag, 0, m_Font.GetSubData(), nullptr); + if (error || !m_Font.GetSubData()) + return index; + + m_pTTGSUBTable = std::make_unique<CFX_CTTGSUBTable>(m_Font.GetSubData()); + return GetVerticalGlyph(index, pVertGlyph); +} + +int CPDF_CIDFont::GetVerticalGlyph(int index, bool* pVertGlyph) { + uint32_t vindex = m_pTTGSUBTable->GetVerticalGlyph(index); + if (!vindex) + return index; + + index = vindex; + if (pVertGlyph) + *pVertGlyph = true; + return index; +} + +int CPDF_CIDFont::GlyphFromCharCode(uint32_t charcode, bool* pVertGlyph) { + if (pVertGlyph) + *pVertGlyph = false; + + if (!m_pFontFile && (!m_pStreamAcc || m_pCID2UnicodeMap)) { + uint16_t cid = CIDFromCharCode(charcode); + wchar_t unicode = 0; + if (m_bCIDIsGID) { +#if BUILDFLAG(IS_APPLE) + if (FontStyleIsSymbolic(m_Flags)) + return cid; + + WideString uni_str = UnicodeFromCharCode(charcode); + if (uni_str.IsEmpty()) + return cid; + + unicode = uni_str[0]; +#else + return cid; +#endif + } else { + if (cid && m_pCID2UnicodeMap && m_pCID2UnicodeMap->IsLoaded()) + unicode = m_pCID2UnicodeMap->UnicodeFromCID(cid); + if (unicode == 0) + unicode = GetUnicodeFromCharCode(charcode); + if (unicode == 0) { + WideString unicode_str = UnicodeFromCharCode(charcode); + if (!unicode_str.IsEmpty()) + unicode = unicode_str[0]; + } + } + FXFT_FaceRec* face = m_Font.GetFaceRec(); + if (unicode == 0) { + if (!m_bAdobeCourierStd) + return charcode ? static_cast<int>(charcode) : -1; + + charcode += 31; + bool bMSUnicode = UseTTCharmapMSUnicode(face); + bool bMacRoman = !bMSUnicode && UseTTCharmapMacRoman(face); + FontEncoding base_encoding = FontEncoding::kStandard; + if (bMSUnicode) + base_encoding = FontEncoding::kWinAnsi; + else if (bMacRoman) + base_encoding = FontEncoding::kMacRoman; + const char* name = + GetAdobeCharName(base_encoding, std::vector<ByteString>(), charcode); + if (!name) + return charcode ? static_cast<int>(charcode) : -1; + + int index = 0; + uint16_t name_unicode = UnicodeFromAdobeName(name); + if (!name_unicode) + return charcode ? static_cast<int>(charcode) : -1; + + if (base_encoding == FontEncoding::kStandard) + return FT_Get_Char_Index(face, name_unicode); + + if (base_encoding == FontEncoding::kWinAnsi) { + index = FT_Get_Char_Index(face, name_unicode); + } else { + DCHECK_EQ(base_encoding, FontEncoding::kMacRoman); + uint32_t maccode = CharCodeFromUnicodeForFreetypeEncoding( + FT_ENCODING_APPLE_ROMAN, name_unicode); + index = maccode ? FT_Get_Char_Index(face, maccode) + : FT_Get_Name_Index(face, name); + } + if (index == 0 || index == 0xffff) + return charcode ? static_cast<int>(charcode) : -1; + return index; + } + if (m_Charset == CIDSET_JAPAN1) { + if (unicode == '\\') { + unicode = '/'; +#if !BUILDFLAG(IS_APPLE) + } else if (unicode == 0xa5) { + unicode = 0x5c; +#endif + } + } + if (!face) + return unicode; + + int err = FXFT_Select_Charmap(face, FT_ENCODING_UNICODE); + if (err) { + int i; + for (i = 0; i < face->num_charmaps; i++) { + uint32_t ret = CharCodeFromUnicodeForFreetypeEncoding( + FXFT_Get_Charmap_Encoding(face->charmaps[i]), + static_cast<wchar_t>(charcode)); + if (ret == 0) + continue; + FT_Set_Charmap(face, face->charmaps[i]); + unicode = static_cast<wchar_t>(ret); + break; + } + if (i == face->num_charmaps && i) { + FT_Set_Charmap(face, face->charmaps[0]); + unicode = static_cast<wchar_t>(charcode); + } + } + if (face->charmap) { + int index = GetGlyphIndex(unicode, pVertGlyph); + return index != 0 ? index : -1; + } + return unicode; + } + + if (!m_Font.GetFaceRec()) + return -1; + + uint16_t cid = CIDFromCharCode(charcode); + if (!m_pStreamAcc) { + if (m_FontType == CIDFontType::kType1) + return cid; + if (m_pFontFile && m_pCMap->IsDirectCharcodeToCIDTableIsEmpty()) + return cid; + + FT_CharMap charmap = m_Font.GetFaceRec()->charmap; + if (!charmap || m_pCMap->GetCoding() == CIDCoding::kUNKNOWN) + return cid; + + if (FXFT_Get_Charmap_Encoding(charmap) == FT_ENCODING_UNICODE) { + WideString unicode_str = UnicodeFromCharCode(charcode); + if (unicode_str.IsEmpty()) + return -1; + + charcode = unicode_str[0]; + } + return GetGlyphIndex(charcode, pVertGlyph); + } + uint32_t byte_pos = cid * 2; + if (byte_pos + 2 > m_pStreamAcc->GetSize()) + return -1; + + pdfium::span<const uint8_t> span = m_pStreamAcc->GetSpan().subspan(byte_pos); + return span[0] * 256 + span[1]; +} + +uint32_t CPDF_CIDFont::GetNextChar(ByteStringView pString, + size_t* pOffset) const { + return m_pCMap->GetNextChar(pString, pOffset); +} + +int CPDF_CIDFont::GetCharSize(uint32_t charcode) const { + return m_pCMap->GetCharSize(charcode); +} + +size_t CPDF_CIDFont::CountChar(ByteStringView pString) const { + return m_pCMap->CountChar(pString); +} + +int CPDF_CIDFont::AppendChar(char* str, uint32_t charcode) const { + return m_pCMap->AppendChar(str, charcode); +} + +bool CPDF_CIDFont::IsUnicodeCompatible() const { + if (m_pCID2UnicodeMap && m_pCID2UnicodeMap->IsLoaded() && m_pCMap->IsLoaded()) + return true; + return m_pCMap->GetCoding() != CIDCoding::kUNKNOWN; +} + +void CPDF_CIDFont::LoadSubstFont() { + FX_SAFE_INT32 safeStemV(m_StemV); + safeStemV *= 5; + m_Font.LoadSubst(m_BaseFontName, m_FontType == CIDFontType::kTrueType, + m_Flags, safeStemV.ValueOrDefault(FXFONT_FW_NORMAL), + m_ItalicAngle, kCharsetCodePages[m_Charset], + IsVertWriting()); +} + // static float CPDF_CIDFont::CIDTransformToFloat(uint8_t ch) { return (ch < 128 ? ch : ch - 255) * (1.0f / 127); } void CPDF_CIDFont::LoadGB2312() { - m_BaseFontName = m_pFontDict->GetStringFor("BaseFont"); + m_BaseFontName = m_pFontDict->GetByteStringFor("BaseFont"); m_Charset = CIDSET_GB1; - CPDF_CMapManager* manager = CPDF_FontGlobals::GetInstance()->GetCMapManager(); - m_pCMap = manager->GetPredefinedCMap("GBK-EUC-H"); - m_pCID2UnicodeMap = manager->GetCID2UnicodeMap(m_Charset); - const CPDF_Dictionary* pFontDesc = m_pFontDict->GetDictFor("FontDescriptor"); + auto* pFontGlobals = CPDF_FontGlobals::GetInstance(); + m_pCMap = pFontGlobals->GetPredefinedCMap("GBK-EUC-H"); + m_pCID2UnicodeMap = pFontGlobals->GetCID2UnicodeMap(m_Charset); + RetainPtr<const CPDF_Dictionary> pFontDesc = + m_pFontDict->GetDictFor("FontDescriptor"); if (pFontDesc) - LoadFontDescriptor(pFontDesc); + LoadFontDescriptor(pFontDesc.Get()); if (!IsEmbedded()) LoadSubstFont(); @@ -833,14 +879,14 @@ m_bAnsiWidthsFixed = true; } -const uint8_t* CPDF_CIDFont::GetCIDTransform(uint16_t CID) const { +const uint8_t* CPDF_CIDFont::GetCIDTransform(uint16_t cid) const { if (m_Charset != CIDSET_JAPAN1 || m_pFontFile) return nullptr; - const auto* pEnd = g_Japan1_VertCIDs + FX_ArraySize(g_Japan1_VertCIDs); + const auto* pEnd = kJapan1VerticalCIDs + std::size(kJapan1VerticalCIDs); const auto* pTransform = std::lower_bound( - g_Japan1_VertCIDs, pEnd, CID, + kJapan1VerticalCIDs, pEnd, cid, [](const CIDTransform& entry, uint16_t cid) { return entry.cid < cid; }); - return (pTransform < pEnd && CID == pTransform->cid) ? &pTransform->a + return (pTransform < pEnd && cid == pTransform->cid) ? &pTransform->a : nullptr; }
diff --git a/core/fpdfapi/font/cpdf_cidfont.h b/core/fpdfapi/font/cpdf_cidfont.h index ce00e1d..fe270a2 100644 --- a/core/fpdfapi/font/cpdf_cidfont.h +++ b/core/fpdfapi/font/cpdf_cidfont.h
@@ -1,4 +1,4 @@ -// Copyright 2016 PDFium Authors. All rights reserved. +// Copyright 2016 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -7,12 +7,14 @@ #ifndef CORE_FPDFAPI_FONT_CPDF_CIDFONT_H_ #define CORE_FPDFAPI_FONT_CPDF_CIDFONT_H_ +#include <stdint.h> + #include <memory> #include <vector> #include "core/fpdfapi/font/cpdf_font.h" +#include "core/fxcrt/fx_coordinates.h" #include "core/fxcrt/fx_string.h" -#include "core/fxcrt/fx_system.h" #include "core/fxcrt/retain_ptr.h" #include "core/fxcrt/unowned_ptr.h" @@ -27,16 +29,13 @@ }; class CFX_CTTGSUBTable; -class CPDF_Array; class CPDF_CID2UnicodeMap; class CPDF_CMap; class CPDF_StreamAcc; class CPDF_CIDFont final : public CPDF_Font { public: - template <typename T, typename... Args> - friend RetainPtr<T> pdfium::MakeRetain(Args&&... args); - + CONSTRUCT_VIA_MAKE_RETAIN; ~CPDF_CIDFont() override; static float CIDTransformToFloat(uint8_t ch); @@ -46,7 +45,7 @@ const CPDF_CIDFont* AsCIDFont() const override; CPDF_CIDFont* AsCIDFont() override; int GlyphFromCharCode(uint32_t charcode, bool* pVertGlyph) override; - uint32_t GetCharWidthF(uint32_t charcode) override; + int GetCharWidthF(uint32_t charcode) override; FX_RECT GetCharBBox(uint32_t charcode) override; uint32_t GetNextChar(ByteStringView pString, size_t* pOffset) const override; size_t CountChar(ByteStringView pString) const override; @@ -58,20 +57,22 @@ uint32_t CharCodeFromUnicode(wchar_t Unicode) const override; uint16_t CIDFromCharCode(uint32_t charcode) const; - const uint8_t* GetCIDTransform(uint16_t CID) const; - short GetVertWidth(uint16_t CID) const; - void GetVertOrigin(uint16_t CID, short& vx, short& vy) const; + const uint8_t* GetCIDTransform(uint16_t cid) const; + int16_t GetVertWidth(uint16_t cid) const; + CFX_Point16 GetVertOrigin(uint16_t cid) const; int GetCharSize(uint32_t charcode) const; private: - CPDF_CIDFont(CPDF_Document* pDocument, CPDF_Dictionary* pFontDict); + enum class CIDFontType : bool { + kType1, // CIDFontType0 + kTrueType // CIDFontType2 + }; + + CPDF_CIDFont(CPDF_Document* pDocument, RetainPtr<CPDF_Dictionary> pFontDict); void LoadGB2312(); int GetGlyphIndex(uint32_t unicodeb, bool* pVertGlyph); int GetVerticalGlyph(int index, bool* pVertGlyph); - void LoadMetricsArray(const CPDF_Array* pArray, - std::vector<uint32_t>* result, - int nElements); void LoadSubstFont(); wchar_t GetUnicodeFromCharCode(uint32_t charcode) const; @@ -79,16 +80,16 @@ UnownedPtr<const CPDF_CID2UnicodeMap> m_pCID2UnicodeMap; RetainPtr<CPDF_StreamAcc> m_pStreamAcc; std::unique_ptr<CFX_CTTGSUBTable> m_pTTGSUBTable; - bool m_bType1 = false; + CIDFontType m_FontType = CIDFontType::kTrueType; bool m_bCIDIsGID = false; bool m_bAnsiWidthsFixed = false; bool m_bAdobeCourierStd = false; CIDSet m_Charset = CIDSET_UNKNOWN; - uint16_t m_DefaultWidth = 1000; - short m_DefaultVY = 880; - short m_DefaultW1 = -1000; - std::vector<uint32_t> m_WidthList; - std::vector<uint32_t> m_VertMetrics; + int16_t m_DefaultWidth = 1000; + int16_t m_DefaultVY = 880; + int16_t m_DefaultW1 = -1000; + std::vector<int> m_WidthList; + std::vector<int> m_VertMetrics; FX_RECT m_CharBBox[256]; };
diff --git a/core/fpdfapi/font/cpdf_cidfont_unittest.cpp b/core/fpdfapi/font/cpdf_cidfont_unittest.cpp index 225ea3a..4bc7426 100644 --- a/core/fpdfapi/font/cpdf_cidfont_unittest.cpp +++ b/core/fpdfapi/font/cpdf_cidfont_unittest.cpp
@@ -1,4 +1,4 @@ -// Copyright 2019 PDFium Authors. All rights reserved. +// Copyright 2019 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -6,24 +6,18 @@ #include <utility> -#include "core/fpdfapi/page/cpdf_docpagedata.h" -#include "core/fpdfapi/page/cpdf_pagemodule.h" +#include "core/fpdfapi/page/test_with_page_module.h" #include "core/fpdfapi/parser/cpdf_array.h" #include "core/fpdfapi/parser/cpdf_dictionary.h" #include "core/fpdfapi/parser/cpdf_document.h" #include "core/fpdfapi/parser/cpdf_name.h" -#include "core/fpdfapi/render/cpdf_docrenderdata.h" +#include "core/fpdfapi/parser/cpdf_test_document.h" #include "testing/gtest/include/gtest/gtest.h" -class CPDF_CIDFontTest : public testing::Test { - protected: - void SetUp() override { CPDF_PageModule::Create(); } - void TearDown() override { CPDF_PageModule::Destroy(); } -}; +using CPDF_CIDFontTest = TestWithPageModule; TEST_F(CPDF_CIDFontTest, BUG_920636) { - CPDF_Document doc(pdfium::MakeUnique<CPDF_DocRenderData>(), - pdfium::MakeUnique<CPDF_DocPageData>()); + CPDF_TestDocument doc; auto font_dict = pdfium::MakeRetain<CPDF_Dictionary>(); font_dict->SetNewFor<CPDF_Name>("Encoding", "Identity−H"); @@ -32,12 +26,12 @@ { auto descendant_font = pdfium::MakeRetain<CPDF_Dictionary>(); descendant_font->SetNewFor<CPDF_Name>("BaseFont", "CourierStd"); - descendant_fonts->Add(std::move(descendant_font)); + descendant_fonts->Append(std::move(descendant_font)); } font_dict->SetFor("DescendantFonts", std::move(descendant_fonts)); } - auto font = pdfium::MakeRetain<CPDF_CIDFont>(&doc, font_dict.Get()); + auto font = pdfium::MakeRetain<CPDF_CIDFont>(&doc, std::move(font_dict)); ASSERT_TRUE(font->Load()); // It would be nice if we can test more values here. However, the glyph
diff --git a/core/fpdfapi/font/cpdf_cmap.cpp b/core/fpdfapi/font/cpdf_cmap.cpp index 844bc5f..d5fa61b 100644 --- a/core/fpdfapi/font/cpdf_cmap.cpp +++ b/core/fpdfapi/font/cpdf_cmap.cpp
@@ -1,4 +1,4 @@ -// Copyright 2017 PDFium Authors. All rights reserved. +// Copyright 2017 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -6,7 +6,6 @@ #include "core/fpdfapi/font/cpdf_cmap.h" -#include <memory> #include <utility> #include <vector> @@ -14,6 +13,7 @@ #include "core/fpdfapi/font/cpdf_cmapparser.h" #include "core/fpdfapi/font/cpdf_fontglobals.h" #include "core/fpdfapi/parser/cpdf_simple_parser.h" +#include "third_party/base/check.h" namespace { @@ -34,151 +34,176 @@ constexpr PredefinedCMap kPredefinedCMaps[] = { {"GB-EUC", CIDSET_GB1, - CIDCODING_GB, + CIDCoding::kGB, CPDF_CMap::MixedTwoBytes, 1, {{0xa1, 0xfe}}}, {"GBpc-EUC", CIDSET_GB1, - CIDCODING_GB, + CIDCoding::kGB, CPDF_CMap::MixedTwoBytes, 1, {{0xa1, 0xfc}}}, {"GBK-EUC", CIDSET_GB1, - CIDCODING_GB, + CIDCoding::kGB, CPDF_CMap::MixedTwoBytes, 1, {{0x81, 0xfe}}}, {"GBKp-EUC", CIDSET_GB1, - CIDCODING_GB, + CIDCoding::kGB, CPDF_CMap::MixedTwoBytes, 1, {{0x81, 0xfe}}}, {"GBK2K-EUC", CIDSET_GB1, - CIDCODING_GB, + CIDCoding::kGB, CPDF_CMap::MixedTwoBytes, 1, {{0x81, 0xfe}}}, {"GBK2K", CIDSET_GB1, - CIDCODING_GB, + CIDCoding::kGB, CPDF_CMap::MixedTwoBytes, 1, {{0x81, 0xfe}}}, - {"UniGB-UCS2", CIDSET_GB1, CIDCODING_UCS2, CPDF_CMap::TwoBytes, 0, {}}, - {"UniGB-UTF16", CIDSET_GB1, CIDCODING_UTF16, CPDF_CMap::TwoBytes, 0, {}}, + {"UniGB-UCS2", CIDSET_GB1, CIDCoding::kUCS2, CPDF_CMap::TwoBytes, 0, {}}, + {"UniGB-UTF16", CIDSET_GB1, CIDCoding::kUTF16, CPDF_CMap::TwoBytes, 0, {}}, {"B5pc", CIDSET_CNS1, - CIDCODING_BIG5, + CIDCoding::kBIG5, CPDF_CMap::MixedTwoBytes, 1, {{0xa1, 0xfc}}}, {"HKscs-B5", CIDSET_CNS1, - CIDCODING_BIG5, + CIDCoding::kBIG5, CPDF_CMap::MixedTwoBytes, 1, {{0x88, 0xfe}}}, {"ETen-B5", CIDSET_CNS1, - CIDCODING_BIG5, + CIDCoding::kBIG5, CPDF_CMap::MixedTwoBytes, 1, {{0xa1, 0xfe}}}, {"ETenms-B5", CIDSET_CNS1, - CIDCODING_BIG5, + CIDCoding::kBIG5, CPDF_CMap::MixedTwoBytes, 1, {{0xa1, 0xfe}}}, - {"UniCNS-UCS2", CIDSET_CNS1, CIDCODING_UCS2, CPDF_CMap::TwoBytes, 0, {}}, - {"UniCNS-UTF16", CIDSET_CNS1, CIDCODING_UTF16, CPDF_CMap::TwoBytes, 0, {}}, + {"UniCNS-UCS2", CIDSET_CNS1, CIDCoding::kUCS2, CPDF_CMap::TwoBytes, 0, {}}, + {"UniCNS-UTF16", + CIDSET_CNS1, + CIDCoding::kUTF16, + CPDF_CMap::TwoBytes, + 0, + {}}, {"83pv-RKSJ", CIDSET_JAPAN1, - CIDCODING_JIS, + CIDCoding::kJIS, CPDF_CMap::MixedTwoBytes, 2, {{0x81, 0x9f}, {0xe0, 0xfc}}}, {"90ms-RKSJ", CIDSET_JAPAN1, - CIDCODING_JIS, + CIDCoding::kJIS, CPDF_CMap::MixedTwoBytes, 2, {{0x81, 0x9f}, {0xe0, 0xfc}}}, {"90msp-RKSJ", CIDSET_JAPAN1, - CIDCODING_JIS, + CIDCoding::kJIS, CPDF_CMap::MixedTwoBytes, 2, {{0x81, 0x9f}, {0xe0, 0xfc}}}, {"90pv-RKSJ", CIDSET_JAPAN1, - CIDCODING_JIS, + CIDCoding::kJIS, CPDF_CMap::MixedTwoBytes, 2, {{0x81, 0x9f}, {0xe0, 0xfc}}}, {"Add-RKSJ", CIDSET_JAPAN1, - CIDCODING_JIS, + CIDCoding::kJIS, CPDF_CMap::MixedTwoBytes, 2, {{0x81, 0x9f}, {0xe0, 0xfc}}}, {"EUC", CIDSET_JAPAN1, - CIDCODING_JIS, + CIDCoding::kJIS, CPDF_CMap::MixedTwoBytes, 2, {{0x8e, 0x8e}, {0xa1, 0xfe}}}, - {"H", CIDSET_JAPAN1, CIDCODING_JIS, CPDF_CMap::TwoBytes, 1, {{0x21, 0x7e}}}, - {"V", CIDSET_JAPAN1, CIDCODING_JIS, CPDF_CMap::TwoBytes, 1, {{0x21, 0x7e}}}, + {"H", + CIDSET_JAPAN1, + CIDCoding::kJIS, + CPDF_CMap::TwoBytes, + 1, + {{0x21, 0x7e}}}, + {"V", + CIDSET_JAPAN1, + CIDCoding::kJIS, + CPDF_CMap::TwoBytes, + 1, + {{0x21, 0x7e}}}, {"Ext-RKSJ", CIDSET_JAPAN1, - CIDCODING_JIS, + CIDCoding::kJIS, CPDF_CMap::MixedTwoBytes, 2, {{0x81, 0x9f}, {0xe0, 0xfc}}}, - {"UniJIS-UCS2", CIDSET_JAPAN1, CIDCODING_UCS2, CPDF_CMap::TwoBytes, 0, {}}, + {"UniJIS-UCS2", + CIDSET_JAPAN1, + CIDCoding::kUCS2, + CPDF_CMap::TwoBytes, + 0, + {}}, {"UniJIS-UCS2-HW", CIDSET_JAPAN1, - CIDCODING_UCS2, + CIDCoding::kUCS2, CPDF_CMap::TwoBytes, 0, {}}, {"UniJIS-UTF16", CIDSET_JAPAN1, - CIDCODING_UTF16, + CIDCoding::kUTF16, CPDF_CMap::TwoBytes, 0, {}}, {"KSC-EUC", CIDSET_KOREA1, - CIDCODING_KOREA, + CIDCoding::kKOREA, CPDF_CMap::MixedTwoBytes, 1, {{0xa1, 0xfe}}}, {"KSCms-UHC", CIDSET_KOREA1, - CIDCODING_KOREA, + CIDCoding::kKOREA, CPDF_CMap::MixedTwoBytes, 1, {{0x81, 0xfe}}}, {"KSCms-UHC-HW", CIDSET_KOREA1, - CIDCODING_KOREA, + CIDCoding::kKOREA, CPDF_CMap::MixedTwoBytes, 1, {{0x81, 0xfe}}}, {"KSCpc-EUC", CIDSET_KOREA1, - CIDCODING_KOREA, + CIDCoding::kKOREA, CPDF_CMap::MixedTwoBytes, 1, {{0xa1, 0xfd}}}, - {"UniKS-UCS2", CIDSET_KOREA1, CIDCODING_UCS2, CPDF_CMap::TwoBytes, 0, {}}, - {"UniKS-UTF16", CIDSET_KOREA1, CIDCODING_UTF16, CPDF_CMap::TwoBytes, 0, {}}, + {"UniKS-UCS2", CIDSET_KOREA1, CIDCoding::kUCS2, CPDF_CMap::TwoBytes, 0, {}}, + {"UniKS-UTF16", + CIDSET_KOREA1, + CIDCoding::kUTF16, + CPDF_CMap::TwoBytes, + 0, + {}}, }; const PredefinedCMap* GetPredefinedCMap(ByteStringView cmapid) { @@ -255,12 +280,21 @@ return 1; } +const fxcmap::CMap* FindEmbeddedCMap(pdfium::span<const fxcmap::CMap> pCMaps, + ByteStringView bsName) { + for (size_t i = 0; i < pCMaps.size(); i++) { + if (bsName == pCMaps[i].m_Name) + return &pCMaps[i]; + } + return nullptr; +} + } // namespace CPDF_CMap::CPDF_CMap(ByteStringView bsPredefinedName) : m_bVertical(bsPredefinedName.Back() == 'V') { if (bsPredefinedName == "Identity-H" || bsPredefinedName == "Identity-V") { - m_Coding = CIDCODING_CID; + m_Coding = CIDCoding::kCID; m_bLoaded = true; return; } @@ -284,10 +318,10 @@ } CPDF_CMap::CPDF_CMap(pdfium::span<const uint8_t> spEmbeddedData) - : m_DirectCharcodeToCIDTable(65536) { + : m_DirectCharcodeToCIDTable(kDirectMapTableSize) { CPDF_CMapParser parser(this); CPDF_SimpleParser syntax(spEmbeddedData); - while (1) { + while (true) { ByteStringView word = syntax.GetWord(); if (word.IsEmpty()) break; @@ -299,17 +333,18 @@ CPDF_CMap::~CPDF_CMap() = default; uint16_t CPDF_CMap::CIDFromCharCode(uint32_t charcode) const { - if (m_Coding == CIDCODING_CID) + if (m_Coding == CIDCoding::kCID) return static_cast<uint16_t>(charcode); if (m_pEmbedMap) - return ::CIDFromCharCode(m_pEmbedMap.Get(), charcode); + return fxcmap::CIDFromCharCode(m_pEmbedMap, charcode); if (m_DirectCharcodeToCIDTable.empty()) return static_cast<uint16_t>(charcode); - if (charcode < 0x10000) - return m_DirectCharcodeToCIDTable[charcode]; + auto table_span = m_DirectCharcodeToCIDTable.span(); + if (charcode < table_span.size()) + return table_span[charcode]; auto it = std::lower_bound(m_AdditionalCharcodeToCIDMappings.begin(), m_AdditionalCharcodeToCIDMappings.end(), charcode, @@ -346,7 +381,7 @@ uint8_t codes[4]; int char_size = 1; codes[0] = offset < pBytes.size() ? pBytes[offset++] : 0; - while (1) { + while (true) { int ret = CheckFourByteCodeRange(codes, char_size, m_MixedFourByteLeadingRanges); if (ret == 0) @@ -361,7 +396,6 @@ return 0; codes[char_size++] = pBytes[offset++]; } - break; } } return 0; @@ -466,7 +500,7 @@ } void CPDF_CMap::SetAdditionalMappings(std::vector<CIDRange> mappings) { - ASSERT(m_AdditionalCharcodeToCIDMappings.empty()); + DCHECK(m_AdditionalCharcodeToCIDMappings.empty()); if (m_CodingScheme != MixedFourBytes || mappings.empty()) return;
diff --git a/core/fpdfapi/font/cpdf_cmap.h b/core/fpdfapi/font/cpdf_cmap.h index e2caf8d..cc186e8 100644 --- a/core/fpdfapi/font/cpdf_cmap.h +++ b/core/fpdfapi/font/cpdf_cmap.h
@@ -1,4 +1,4 @@ -// Copyright 2017 PDFium Authors. All rights reserved. +// Copyright 2017 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -7,27 +7,35 @@ #ifndef CORE_FPDFAPI_FONT_CPDF_CMAP_H_ #define CORE_FPDFAPI_FONT_CPDF_CMAP_H_ +#include <stdint.h> + #include <vector> #include "core/fpdfapi/font/cpdf_cidfont.h" +#include "core/fxcrt/fixed_zeroed_data_vector.h" #include "core/fxcrt/retain_ptr.h" +#include "core/fxcrt/unowned_ptr.h" #include "third_party/base/span.h" -struct FXCMAP_CMap; +namespace fxcmap { +struct CMap; +} -enum CIDCoding : uint8_t { - CIDCODING_UNKNOWN = 0, - CIDCODING_GB, - CIDCODING_BIG5, - CIDCODING_JIS, - CIDCODING_KOREA, - CIDCODING_UCS2, - CIDCODING_CID, - CIDCODING_UTF16, +enum class CIDCoding : uint8_t { + kUNKNOWN = 0, + kGB, + kBIG5, + kJIS, + kKOREA, + kUCS2, + kCID, + kUTF16, }; class CPDF_CMap final : public Retainable { public: + static constexpr size_t kDirectMapTableSize = 65536; + enum CodingScheme : uint8_t { OneByte, TwoBytes, @@ -47,8 +55,7 @@ uint16_t m_StartCID; }; - template <typename T, typename... Args> - friend RetainPtr<T> pdfium::MakeRetain(Args&&... args); + CONSTRUCT_VIA_MAKE_RETAIN; bool IsLoaded() const { return m_bLoaded; } bool IsVertWriting() const { return m_bVertical; } @@ -65,13 +72,13 @@ void SetAdditionalMappings(std::vector<CIDRange> mappings); void SetMixedFourByteLeadingRanges(std::vector<CodeRange> ranges); - int GetCoding() const { return m_Coding; } - const FXCMAP_CMap* GetEmbedMap() const { return m_pEmbedMap.Get(); } + CIDCoding GetCoding() const { return m_Coding; } + const fxcmap::CMap* GetEmbedMap() const { return m_pEmbedMap; } CIDSet GetCharset() const { return m_Charset; } void SetCharset(CIDSet set) { m_Charset = set; } void SetDirectCharcodeToCIDTable(size_t idx, uint16_t val) { - m_DirectCharcodeToCIDTable[idx] = val; + m_DirectCharcodeToCIDTable.writable_span()[idx] = val; } bool IsDirectCharcodeToCIDTableIsEmpty() const { return m_DirectCharcodeToCIDTable.empty(); @@ -86,12 +93,12 @@ bool m_bVertical = false; CIDSet m_Charset = CIDSET_UNKNOWN; CodingScheme m_CodingScheme = TwoBytes; - int m_Coding = CIDCODING_UNKNOWN; + CIDCoding m_Coding = CIDCoding::kUNKNOWN; std::vector<bool> m_MixedTwoByteLeadingBytes; std::vector<CodeRange> m_MixedFourByteLeadingRanges; - std::vector<uint16_t> m_DirectCharcodeToCIDTable; + FixedZeroedDataVector<uint16_t> m_DirectCharcodeToCIDTable; std::vector<CIDRange> m_AdditionalCharcodeToCIDMappings; - UnownedPtr<const FXCMAP_CMap> m_pEmbedMap; + UnownedPtr<const fxcmap::CMap> m_pEmbedMap; }; #endif // CORE_FPDFAPI_FONT_CPDF_CMAP_H_
diff --git a/core/fpdfapi/font/cpdf_cmapmanager.cpp b/core/fpdfapi/font/cpdf_cmapmanager.cpp deleted file mode 100644 index 726b648..0000000 --- a/core/fpdfapi/font/cpdf_cmapmanager.cpp +++ /dev/null
@@ -1,48 +0,0 @@ -// Copyright 2017 PDFium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com - -#include "core/fpdfapi/font/cpdf_cmapmanager.h" - -#include <utility> - -#include "core/fpdfapi/font/cpdf_cid2unicodemap.h" -#include "core/fpdfapi/font/cpdf_cmap.h" -#include "third_party/base/ptr_util.h" - -namespace { - -RetainPtr<const CPDF_CMap> LoadPredefinedCMap(ByteStringView name) { - if (!name.IsEmpty() && name[0] == '/') - name = name.Last(name.GetLength() - 1); - return pdfium::MakeRetain<CPDF_CMap>(name); -} - -} // namespace - -CPDF_CMapManager::CPDF_CMapManager() = default; - -CPDF_CMapManager::~CPDF_CMapManager() = default; - -RetainPtr<const CPDF_CMap> CPDF_CMapManager::GetPredefinedCMap( - const ByteString& name) { - auto it = m_CMaps.find(name); - if (it != m_CMaps.end()) - return it->second; - - RetainPtr<const CPDF_CMap> pCMap = LoadPredefinedCMap(name.AsStringView()); - if (!name.IsEmpty()) - m_CMaps[name] = pCMap; - - return pCMap; -} - -CPDF_CID2UnicodeMap* CPDF_CMapManager::GetCID2UnicodeMap(CIDSet charset) { - if (!m_CID2UnicodeMaps[charset]) { - m_CID2UnicodeMaps[charset] = - pdfium::MakeUnique<CPDF_CID2UnicodeMap>(charset); - } - return m_CID2UnicodeMaps[charset].get(); -}
diff --git a/core/fpdfapi/font/cpdf_cmapmanager.h b/core/fpdfapi/font/cpdf_cmapmanager.h deleted file mode 100644 index bc8d4e9..0000000 --- a/core/fpdfapi/font/cpdf_cmapmanager.h +++ /dev/null
@@ -1,30 +0,0 @@ -// Copyright 2017 PDFium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com - -#ifndef CORE_FPDFAPI_FONT_CPDF_CMAPMANAGER_H_ -#define CORE_FPDFAPI_FONT_CPDF_CMAPMANAGER_H_ - -#include <map> -#include <memory> - -#include "core/fpdfapi/font/cpdf_cidfont.h" -#include "core/fxcrt/bytestring.h" -#include "core/fxcrt/retain_ptr.h" - -class CPDF_CMapManager { - public: - CPDF_CMapManager(); - ~CPDF_CMapManager(); - - RetainPtr<const CPDF_CMap> GetPredefinedCMap(const ByteString& name); - CPDF_CID2UnicodeMap* GetCID2UnicodeMap(CIDSet charset); - - private: - std::map<ByteString, RetainPtr<const CPDF_CMap>> m_CMaps; - std::unique_ptr<CPDF_CID2UnicodeMap> m_CID2UnicodeMaps[CIDSET_NUM_SETS]; -}; - -#endif // CORE_FPDFAPI_FONT_CPDF_CMAPMANAGER_H_
diff --git a/core/fpdfapi/font/cpdf_cmapparser.cpp b/core/fpdfapi/font/cpdf_cmapparser.cpp index d1fe51c..87a5907 100644 --- a/core/fpdfapi/font/cpdf_cmapparser.cpp +++ b/core/fpdfapi/font/cpdf_cmapparser.cpp
@@ -1,4 +1,4 @@ -// Copyright 2014 PDFium Authors. All rights reserved. +// Copyright 2014 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -6,7 +6,9 @@ #include "core/fpdfapi/font/cpdf_cmapparser.h" -#include <vector> +#include <ctype.h> + +#include <iterator> #include "core/fpdfapi/cmaps/fpdf_cmaps.h" #include "core/fpdfapi/parser/cpdf_array.h" @@ -14,8 +16,8 @@ #include "core/fpdfapi/parser/cpdf_simple_parser.h" #include "core/fxcrt/fx_extension.h" #include "core/fxcrt/fx_safe_types.h" -#include "core/fxge/fx_freetype.h" -#include "third_party/base/logging.h" +#include "core/fxge/freetype/fx_freetype.h" +#include "third_party/base/check.h" namespace { @@ -35,7 +37,7 @@ } void CPDF_CMapParser::ParseWord(ByteStringView word) { - ASSERT(!word.IsEmpty()); + DCHECK(!word.IsEmpty()); if (word == "begincidchar") { m_Status = kProcessingCidChar; @@ -78,7 +80,7 @@ } void CPDF_CMapParser::HandleCid(ByteStringView word) { - ASSERT(m_Status == kProcessingCidChar || m_Status == kProcessingCidRange); + DCHECK(m_Status == kProcessingCidChar || m_Status == kProcessingCidRange); bool bChar = m_Status == kProcessingCidChar; m_CodePoints[m_CodeSeq] = GetCode(word); @@ -97,7 +99,7 @@ EndCode = m_CodePoints[1]; StartCID = static_cast<uint16_t>(m_CodePoints[2]); } - if (EndCode < 0x10000) { + if (EndCode < CPDF_CMap::kDirectMapTableSize) { for (uint32_t code = StartCode; code <= EndCode; code++) { m_pCMap->SetDirectCharcodeToCIDTable( code, static_cast<uint16_t>(StartCID + code - StartCode)); @@ -114,7 +116,7 @@ return; if (m_CodeSeq % 2) { - Optional<CPDF_CMap::CodeRange> range = + absl::optional<CPDF_CMap::CodeRange> range = GetCodeRange(m_LastWord.AsStringView(), word); if (range.has_value()) m_PendingRanges.push_back(range.value()); @@ -146,7 +148,7 @@ FX_SAFE_UINT32 num = 0; if (word[0] == '<') { - for (size_t i = 1; i < word.GetLength() && std::isxdigit(word[i]); ++i) { + for (size_t i = 1; i < word.GetLength() && isxdigit(word[i]); ++i) { num = num * 16 + FXSYS_HexCharToInt(word[i]); if (!num.IsValid()) return 0; @@ -154,7 +156,7 @@ return num.ValueOrDie(); } - for (size_t i = 0; i < word.GetLength() && std::isdigit(word[i]); ++i) { + for (size_t i = 0; i < word.GetLength() && isdigit(word[i]); ++i) { num = num * 10 + FXSYS_DecimalCharToInt(static_cast<wchar_t>(word[i])); if (!num.IsValid()) return 0; @@ -163,11 +165,11 @@ } // static -Optional<CPDF_CMap::CodeRange> CPDF_CMapParser::GetCodeRange( +absl::optional<CPDF_CMap::CodeRange> CPDF_CMapParser::GetCodeRange( ByteStringView first, ByteStringView second) { if (first.IsEmpty() || first[0] != '<') - return pdfium::nullopt; + return absl::nullopt; size_t i; for (i = 1; i < first.GetLength(); ++i) { @@ -176,7 +178,7 @@ } size_t char_size = (i - 1) / 2; if (char_size > 4) - return pdfium::nullopt; + return absl::nullopt; CPDF_CMap::CodeRange range; range.m_CharSize = char_size; @@ -203,10 +205,10 @@ CIDSet CPDF_CMapParser::CharsetFromOrdering(ByteStringView ordering) { static const char* const kCharsetNames[CIDSET_NUM_SETS] = { nullptr, "GB1", "CNS1", "Japan1", "Korea1", "UCS"}; - static_assert(FX_ArraySize(kCharsetNames) == CIDSET_NUM_SETS, + static_assert(std::size(kCharsetNames) == CIDSET_NUM_SETS, "Too many CID sets"); - for (size_t charset = 1; charset < FX_ArraySize(kCharsetNames); ++charset) { + for (size_t charset = 1; charset < std::size(kCharsetNames); ++charset) { if (ordering == kCharsetNames[charset]) return static_cast<CIDSet>(charset); }
diff --git a/core/fpdfapi/font/cpdf_cmapparser.h b/core/fpdfapi/font/cpdf_cmapparser.h index b2454af..9219814 100644 --- a/core/fpdfapi/font/cpdf_cmapparser.h +++ b/core/fpdfapi/font/cpdf_cmapparser.h
@@ -1,4 +1,4 @@ -// Copyright 2017 PDFium Authors. All rights reserved. +// Copyright 2017 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -13,7 +13,7 @@ #include "core/fpdfapi/font/cpdf_cidfont.h" #include "core/fpdfapi/font/cpdf_cmap.h" #include "core/fxcrt/unowned_ptr.h" -#include "third_party/base/optional.h" +#include "third_party/abseil-cpp/absl/types/optional.h" class CPDF_CMapParser { public: @@ -43,8 +43,9 @@ void HandleCodeSpaceRange(ByteStringView word); static uint32_t GetCode(ByteStringView word); - static Optional<CPDF_CMap::CodeRange> GetCodeRange(ByteStringView first, - ByteStringView second); + static absl::optional<CPDF_CMap::CodeRange> GetCodeRange( + ByteStringView first, + ByteStringView second); Status m_Status = kStart; int m_CodeSeq = 0; @@ -53,7 +54,7 @@ std::vector<CPDF_CMap::CodeRange> m_PendingRanges; std::vector<CPDF_CMap::CIDRange> m_AdditionalCharcodeToCIDMappings; ByteString m_LastWord; - uint32_t m_CodePoints[4]; + uint32_t m_CodePoints[4] = {}; }; #endif // CORE_FPDFAPI_FONT_CPDF_CMAPPARSER_H_
diff --git a/core/fpdfapi/font/cpdf_cmapparser_unittest.cpp b/core/fpdfapi/font/cpdf_cmapparser_unittest.cpp index da654f3..a9cdc71 100644 --- a/core/fpdfapi/font/cpdf_cmapparser_unittest.cpp +++ b/core/fpdfapi/font/cpdf_cmapparser_unittest.cpp
@@ -1,4 +1,4 @@ -// Copyright 2015 PDFium Authors. All rights reserved. +// Copyright 2015 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -37,7 +37,7 @@ } TEST(cpdf_cmapparser, GetCodeRange) { - Optional<CPDF_CMap::CodeRange> range; + absl::optional<CPDF_CMap::CodeRange> range; // Must start with a < range = CPDF_CMapParser::GetCodeRange("", "");
diff --git a/core/fpdfapi/font/cpdf_font.cpp b/core/fpdfapi/font/cpdf_font.cpp index 326bc6e..36413f8 100644 --- a/core/fpdfapi/font/cpdf_font.cpp +++ b/core/fpdfapi/font/cpdf_font.cpp
@@ -1,4 +1,4 @@ -// Copyright 2016 PDFium Authors. All rights reserved. +// Copyright 2016 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -6,12 +6,13 @@ #include "core/fpdfapi/font/cpdf_font.h" -#include <limits> +#include <algorithm> #include <memory> #include <utility> #include <vector> #include "build/build_config.h" +#include "constants/font_encodings.h" #include "core/fpdfapi/font/cpdf_cidfont.h" #include "core/fpdfapi/font/cpdf_fontencoding.h" #include "core/fpdfapi/font/cpdf_fontglobals.h" @@ -25,13 +26,15 @@ #include "core/fpdfapi/parser/cpdf_name.h" #include "core/fpdfapi/parser/cpdf_stream.h" #include "core/fpdfapi/parser/cpdf_stream_acc.h" -#include "core/fxcrt/fx_memory.h" +#include "core/fxcrt/fx_codepage.h" +#include "core/fxcrt/fx_safe_types.h" +#include "core/fxcrt/stl_util.h" #include "core/fxge/cfx_fontmapper.h" +#include "core/fxge/cfx_substfont.h" +#include "core/fxge/freetype/fx_freetype.h" #include "core/fxge/fx_font.h" -#include "core/fxge/fx_freetype.h" -#include "third_party/base/logging.h" -#include "third_party/base/ptr_util.h" -#include "third_party/base/stl_util.h" +#include "third_party/base/check.h" +#include "third_party/base/numerics/safe_conversions.h" namespace { @@ -45,19 +48,15 @@ } // namespace -CPDF_Font::CPDF_Font(CPDF_Document* pDocument, CPDF_Dictionary* pFontDict) +CPDF_Font::CPDF_Font(CPDF_Document* pDocument, + RetainPtr<CPDF_Dictionary> pFontDict) : m_pDocument(pDocument), - m_pFontDict(pFontDict), - m_BaseFontName(pFontDict->GetStringFor("BaseFont")) {} + m_pFontDict(std::move(pFontDict)), + m_BaseFontName(m_pFontDict->GetByteStringFor("BaseFont")) {} CPDF_Font::~CPDF_Font() { - if (m_pFontFile) { - auto* pPageData = m_pDocument->GetPageData(); - if (pPageData) { - pPageData->MaybePurgeFontFileStreamAcc( - m_pFontFile->GetStream()->AsStream()); - } - } + if (m_pFontFile) + m_pDocument->MaybePurgeFontFileStreamAcc(std::move(m_pFontFile)); } bool CPDF_Font::IsType1Font() const { @@ -108,15 +107,11 @@ return nullptr; } -bool CPDF_Font::IsUnicodeCompatible() const { - return false; -} - size_t CPDF_Font::CountChar(ByteStringView pString) const { return pString.GetLength(); } -#if defined(OS_MACOSX) +#if BUILDFLAG(IS_APPLE) int CPDF_Font::GlyphFromCharCodeExt(uint32_t charcode) { return GlyphFromCharCode(charcode, nullptr); } @@ -194,7 +189,7 @@ } if (m_Descent > 10) m_Descent = -m_Descent; - const CPDF_Array* pBBox = pFontDesc->GetArrayFor("FontBBox"); + RetainPtr<const CPDF_Array> pBBox = pFontDesc->GetArrayFor("FontBBox"); if (pBBox) { m_FontBBox.left = pBBox->GetIntegerAt(0); m_FontBBox.bottom = pBBox->GetIntegerAt(1); @@ -202,7 +197,7 @@ m_FontBBox.top = pBBox->GetIntegerAt(3); } - const CPDF_Stream* pFontFile = pFontDesc->GetStreamFor("FontFile"); + RetainPtr<const CPDF_Stream> pFontFile = pFontDesc->GetStreamFor("FontFile"); if (!pFontFile) pFontFile = pFontDesc->GetStreamFor("FontFile2"); if (!pFontFile) @@ -210,15 +205,13 @@ if (!pFontFile) return; - auto* pData = m_pDocument->GetPageData(); - m_pFontFile = pData->GetFontFileStreamAcc(pFontFile); + const uint64_t key = pFontFile->KeyForCache(); + m_pFontFile = m_pDocument->GetFontFileStreamAcc(std::move(pFontFile)); if (!m_pFontFile) return; - if (!m_Font.LoadEmbedded(m_pFontFile->GetSpan(), IsVertWriting())) { - pData->MaybePurgeFontFileStreamAcc(m_pFontFile->GetStream()->AsStream()); - m_pFontFile = nullptr; - } + if (!m_Font.LoadEmbedded(m_pFontFile->GetSpan(), IsVertWriting(), key)) + m_pDocument->MaybePurgeFontFileStreamAcc(std::move(m_pFontFile)); } void CPDF_Font::CheckFontMetrics() { @@ -243,18 +236,10 @@ m_FontBBox = rect; bFirst = false; } else { - if (m_FontBBox.top < rect.top) { - m_FontBBox.top = rect.top; - } - if (m_FontBBox.right < rect.right) { - m_FontBBox.right = rect.right; - } - if (m_FontBBox.left > rect.left) { - m_FontBBox.left = rect.left; - } - if (m_FontBBox.bottom > rect.bottom) { - m_FontBBox.bottom = rect.bottom; - } + m_FontBBox.left = std::min(m_FontBBox.left, rect.left); + m_FontBBox.top = std::max(m_FontBBox.top, rect.top); + m_FontBBox.right = std::max(m_FontBBox.right, rect.right); + m_FontBBox.bottom = std::min(m_FontBBox.bottom, rect.bottom); } } } @@ -269,16 +254,16 @@ void CPDF_Font::LoadUnicodeMap() const { m_bToUnicodeLoaded = true; - const CPDF_Stream* pStream = m_pFontDict->GetStreamFor("ToUnicode"); + RetainPtr<const CPDF_Stream> pStream = m_pFontDict->GetStreamFor("ToUnicode"); if (!pStream) return; - m_pToUnicodeMap = pdfium::MakeUnique<CPDF_ToUnicodeMap>(pStream); + m_pToUnicodeMap = std::make_unique<CPDF_ToUnicodeMap>(std::move(pStream)); } -uint32_t CPDF_Font::GetStringWidth(ByteStringView pString) { +int CPDF_Font::GetStringWidth(ByteStringView pString) { size_t offset = 0; - uint32_t width = 0; + int width = 0; while (offset < pString.GetLength()) width += GetCharWidthF(GetNextChar(pString, &offset)); return width; @@ -288,7 +273,7 @@ RetainPtr<CPDF_Font> CPDF_Font::GetStockFont(CPDF_Document* pDoc, ByteStringView name) { ByteString fontname(name); - Optional<CFX_FontMapper::StandardFont> font_id = + absl::optional<CFX_FontMapper::StandardFont> font_id = CFX_FontMapper::GetStandardFontName(&fontname); if (!font_id.has_value()) return nullptr; @@ -302,37 +287,39 @@ pDict->SetNewFor<CPDF_Name>("Type", "Font"); pDict->SetNewFor<CPDF_Name>("Subtype", "Type1"); pDict->SetNewFor<CPDF_Name>("BaseFont", fontname); - pDict->SetNewFor<CPDF_Name>("Encoding", "WinAnsiEncoding"); - pFont = CPDF_Font::Create(nullptr, pDict.Get(), nullptr); + pDict->SetNewFor<CPDF_Name>("Encoding", + pdfium::font_encodings::kWinAnsiEncoding); + pFont = CPDF_Font::Create(nullptr, std::move(pDict), nullptr); pFontGlobals->Set(pDoc, font_id.value(), pFont); return pFont; } // static RetainPtr<CPDF_Font> CPDF_Font::Create(CPDF_Document* pDoc, - CPDF_Dictionary* pFontDict, + RetainPtr<CPDF_Dictionary> pFontDict, FormFactoryIface* pFactory) { - ByteString type = pFontDict->GetStringFor("Subtype"); + ByteString type = pFontDict->GetByteStringFor("Subtype"); RetainPtr<CPDF_Font> pFont; if (type == "TrueType") { - ByteString tag = pFontDict->GetStringFor("BaseFont").First(4); - for (size_t i = 0; i < FX_ArraySize(kChineseFontNames); ++i) { + ByteString tag = pFontDict->GetByteStringFor("BaseFont").First(4); + for (size_t i = 0; i < std::size(kChineseFontNames); ++i) { if (tag == ByteString(kChineseFontNames[i], kChineseFontNameSize)) { - const CPDF_Dictionary* pFontDesc = + RetainPtr<const CPDF_Dictionary> pFontDesc = pFontDict->GetDictFor("FontDescriptor"); if (!pFontDesc || !pFontDesc->KeyExist("FontFile2")) - pFont = pdfium::MakeRetain<CPDF_CIDFont>(pDoc, pFontDict); + pFont = pdfium::MakeRetain<CPDF_CIDFont>(pDoc, std::move(pFontDict)); break; } } if (!pFont) - pFont = pdfium::MakeRetain<CPDF_TrueTypeFont>(pDoc, pFontDict); + pFont = pdfium::MakeRetain<CPDF_TrueTypeFont>(pDoc, std::move(pFontDict)); } else if (type == "Type3") { - pFont = pdfium::MakeRetain<CPDF_Type3Font>(pDoc, pFontDict, pFactory); + pFont = pdfium::MakeRetain<CPDF_Type3Font>(pDoc, std::move(pFontDict), + pFactory); } else if (type == "Type0") { - pFont = pdfium::MakeRetain<CPDF_CIDFont>(pDoc, pFontDict); + pFont = pdfium::MakeRetain<CPDF_CIDFont>(pDoc, std::move(pFontDict)); } else { - pFont = pdfium::MakeRetain<CPDF_Type1Font>(pDoc, pFontDict); + pFont = pdfium::MakeRetain<CPDF_Type1Font>(pDoc, std::move(pFontDict)); } if (!pFont->Load()) return nullptr; @@ -356,9 +343,16 @@ return AsType1Font()->IsBase14Font(); } +absl::optional<FX_Charset> CPDF_Font::GetSubstFontCharset() const { + CFX_SubstFont* pFont = m_Font.GetSubstFont(); + if (!pFont) + return absl::nullopt; + return pFont->m_Charset; +} + // static const char* CPDF_Font::GetAdobeCharName( - int iBaseEncoding, + FontEncoding base_encoding, const std::vector<ByteString>& charnames, uint32_t charcode) { if (charcode >= 256) @@ -368,29 +362,30 @@ return charnames[charcode].c_str(); const char* name = nullptr; - if (iBaseEncoding) - name = PDF_CharNameFromPredefinedCharSet(iBaseEncoding, charcode); + if (base_encoding != FontEncoding::kBuiltin) + name = CharNameFromPredefinedCharSet(base_encoding, charcode); if (!name) return nullptr; - ASSERT(name[0]); + DCHECK(name[0]); return name; } uint32_t CPDF_Font::FallbackFontFromCharcode(uint32_t charcode) { if (m_FontFallbacks.empty()) { - m_FontFallbacks.push_back(pdfium::MakeUnique<CFX_Font>()); - pdfium::base::CheckedNumeric<int> safeWeight = m_StemV; + m_FontFallbacks.push_back(std::make_unique<CFX_Font>()); + FX_SAFE_INT32 safeWeight = m_StemV; safeWeight *= 5; m_FontFallbacks[0]->LoadSubst("Arial", IsTrueTypeFont(), m_Flags, safeWeight.ValueOrDefault(FXFONT_FW_NORMAL), - m_ItalicAngle, 0, IsVertWriting()); + m_ItalicAngle, FX_CodePage::kDefANSI, + IsVertWriting()); } return 0; } int CPDF_Font::FallbackGlyphFromCharcode(int fallbackFont, uint32_t charcode) { - if (!pdfium::IndexInBounds(m_FontFallbacks, fallbackFont)) + if (!fxcrt::IndexInBounds(m_FontFallbacks, fallbackFont)) return -1; WideString str = UnicodeFromCharCode(charcode); @@ -410,26 +405,23 @@ } // static -int CPDF_Font::TT2PDF(int m, FXFT_FaceRec* face) { +int CPDF_Font::TT2PDF(FT_Pos m, FXFT_FaceRec* face) { int upm = FXFT_Get_Face_UnitsPerEM(face); if (upm == 0) - return m; + return pdfium::base::saturated_cast<int>(m); - return static_cast<int>( - pdfium::clamp((m * 1000.0 + upm / 2) / upm, - static_cast<double>(std::numeric_limits<int>::min()), - static_cast<double>(std::numeric_limits<int>::max()))); + const double dm = (m * 1000.0 + upm / 2) / upm; + return pdfium::base::saturated_cast<int>(dm); } // static -bool CPDF_Font::FT_UseTTCharmap(FXFT_FaceRec* face, - int platform_id, - int encoding_id) { - auto** pCharMap = FXFT_Get_Face_Charmaps(face); - for (int i = 0; i < FXFT_Get_Face_CharmapCount(face); i++) { - if (FXFT_Get_Charmap_PlatformID(pCharMap[i]) == platform_id && - FXFT_Get_Charmap_EncodingID(pCharMap[i]) == encoding_id) { - FT_Set_Charmap(face, pCharMap[i]); +bool CPDF_Font::UseTTCharmap(FXFT_FaceRec* face, + int platform_id, + int encoding_id) { + for (int i = 0; i < face->num_charmaps; i++) { + if (FXFT_Get_Charmap_PlatformID(face->charmaps[i]) == platform_id && + FXFT_Get_Charmap_EncodingID(face->charmaps[i]) == encoding_id) { + FT_Set_Charmap(face, face->charmaps[i]); return true; } } @@ -437,7 +429,7 @@ } int CPDF_Font::GetFontWeight() const { - pdfium::base::CheckedNumeric<int> safeStemV(m_StemV); + FX_SAFE_INT32 safeStemV(m_StemV); if (m_StemV < 140) safeStemV *= 5; else
diff --git a/core/fpdfapi/font/cpdf_font.h b/core/fpdfapi/font/cpdf_font.h index db776fd..a74cba9 100644 --- a/core/fpdfapi/font/cpdf_font.h +++ b/core/fpdfapi/font/cpdf_font.h
@@ -1,4 +1,4 @@ -// Copyright 2016 PDFium Authors. All rights reserved. +// Copyright 2016 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -7,6 +7,8 @@ #ifndef CORE_FPDFAPI_FONT_CPDF_FONT_H_ #define CORE_FPDFAPI_FONT_CPDF_FONT_H_ +#include <stdint.h> + #include <memory> #include <utility> #include <vector> @@ -15,53 +17,53 @@ #include "core/fpdfapi/parser/cpdf_dictionary.h" #include "core/fpdfapi/parser/cpdf_stream_acc.h" #include "core/fxcrt/fx_string.h" -#include "core/fxcrt/fx_system.h" #include "core/fxcrt/observed_ptr.h" #include "core/fxcrt/retain_ptr.h" #include "core/fxcrt/unowned_ptr.h" #include "core/fxge/cfx_font.h" +#include "core/fxge/freetype/fx_freetype.h" +#include "third_party/abseil-cpp/absl/types/optional.h" class CFX_DIBitmap; -class CFX_SubstFont; class CPDF_CIDFont; class CPDF_Document; -class CPDF_Object; class CPDF_TrueTypeFont; class CPDF_Type1Font; class CPDF_Type3Char; class CPDF_Type3Font; class CPDF_ToUnicodeMap; +enum class FontEncoding; class CPDF_Font : public Retainable, public Observable { public: // Callback mechanism for Type3 fonts to get pixels from forms. class FormIface { public: - virtual ~FormIface() {} + virtual ~FormIface() = default; virtual void ParseContentForType3Char(CPDF_Type3Char* pChar) = 0; virtual bool HasPageObjects() const = 0; virtual CFX_FloatRect CalcBoundingBox() const = 0; - virtual Optional<std::pair<RetainPtr<CFX_DIBitmap>, CFX_Matrix>> + virtual absl::optional<std::pair<RetainPtr<CFX_DIBitmap>, CFX_Matrix>> GetBitmapAndMatrixFromSoleImageOfForm() const = 0; }; // Callback mechanism for Type3 fonts to get new forms from upper layers. class FormFactoryIface { public: - virtual ~FormFactoryIface() {} + virtual ~FormFactoryIface() = default; virtual std::unique_ptr<FormIface> CreateForm( CPDF_Document* pDocument, - CPDF_Dictionary* pPageResources, - CPDF_Stream* pFormStream) = 0; + RetainPtr<CPDF_Dictionary> pPageResources, + RetainPtr<CPDF_Stream> pFormStream) = 0; }; - static const uint32_t kInvalidCharCode = static_cast<uint32_t>(-1); + static constexpr uint32_t kInvalidCharCode = static_cast<uint32_t>(-1); // |pFactory| only required for Type3 fonts. static RetainPtr<CPDF_Font> Create(CPDF_Document* pDoc, - CPDF_Dictionary* pFontDict, + RetainPtr<CPDF_Dictionary> pFontDict, FormFactoryIface* pFactory); static RetainPtr<CPDF_Font> GetStockFont(CPDF_Document* pDoc, ByteStringView fontname); @@ -83,12 +85,12 @@ virtual void WillBeDestroyed(); virtual bool IsVertWriting() const; - virtual bool IsUnicodeCompatible() const; + virtual bool IsUnicodeCompatible() const = 0; virtual uint32_t GetNextChar(ByteStringView pString, size_t* pOffset) const; virtual size_t CountChar(ByteStringView pString) const; virtual int AppendChar(char* buf, uint32_t charcode) const; virtual int GlyphFromCharCode(uint32_t charcode, bool* pVertGlyph) = 0; -#if defined(OS_MACOSX) +#if BUILDFLAG(IS_APPLE) virtual int GlyphFromCharCodeExt(uint32_t charcode); #endif virtual WideString UnicodeFromCharCode(uint32_t charcode) const; @@ -96,9 +98,14 @@ virtual bool HasFontWidths() const; ByteString GetBaseFontName() const { return m_BaseFontName; } - CFX_SubstFont* GetSubstFont() const { return m_Font.GetSubstFont(); } + absl::optional<FX_Charset> GetSubstFontCharset() const; bool IsEmbedded() const { return IsType3Font() || m_pFontFile != nullptr; } - CPDF_Dictionary* GetFontDict() const { return m_pFontDict.Get(); } + RetainPtr<CPDF_Dictionary> GetMutableFontDict() { return m_pFontDict; } + RetainPtr<const CPDF_Dictionary> GetFontDict() const { return m_pFontDict; } + uint32_t GetFontDictObjNum() const { return m_pFontDict->GetObjNum(); } + bool FontDictIs(const CPDF_Dictionary* pThat) const { + return m_pFontDict == pThat; + } void ClearFontDict() { m_pFontDict = nullptr; } bool IsStandardFont() const; bool HasFace() const { return !!m_Font.GetFaceRec(); } @@ -107,32 +114,48 @@ const FX_RECT& GetFontBBox() const { return m_FontBBox; } int GetTypeAscent() const { return m_Ascent; } int GetTypeDescent() const { return m_Descent; } - uint32_t GetStringWidth(ByteStringView pString); + int GetStringWidth(ByteStringView pString); uint32_t FallbackFontFromCharcode(uint32_t charcode); int FallbackGlyphFromCharcode(int fallbackFont, uint32_t charcode); int GetFontFlags() const { return m_Flags; } + int GetItalicAngle() const { return m_ItalicAngle; } int GetFontWeight() const; - virtual uint32_t GetCharWidthF(uint32_t charcode) = 0; + virtual int GetCharWidthF(uint32_t charcode) = 0; virtual FX_RECT GetCharBBox(uint32_t charcode) = 0; // Can return nullptr for stock Type1 fonts. Always returns non-null for other // font types. - CPDF_Document* GetDocument() const { return m_pDocument.Get(); } + CPDF_Document* GetDocument() const { return m_pDocument; } CFX_Font* GetFont() { return &m_Font; } const CFX_Font* GetFont() const { return &m_Font; } CFX_Font* GetFontFallback(int position); - protected: - CPDF_Font(CPDF_Document* pDocument, CPDF_Dictionary* pFontDict); + const ByteString& GetResourceName() const { return m_ResourceName; } + void SetResourceName(const ByteString& name) { m_ResourceName = name; } - static int TT2PDF(int m, FXFT_FaceRec* face); - static bool FT_UseTTCharmap(FXFT_FaceRec* face, - int platform_id, - int encoding_id); - static const char* GetAdobeCharName(int iBaseEncoding, + protected: + CPDF_Font(CPDF_Document* pDocument, RetainPtr<CPDF_Dictionary> pFontDict); + + static int TT2PDF(FT_Pos m, FXFT_FaceRec* face); + + // Commonly used wrappers for UseTTCharmap(). + static bool UseTTCharmapMSUnicode(FXFT_FaceRec* face) { + return UseTTCharmap(face, 3, 1); + } + static bool UseTTCharmapMSSymbol(FXFT_FaceRec* face) { + return UseTTCharmap(face, 3, 0); + } + static bool UseTTCharmapMacRoman(FXFT_FaceRec* face) { + return UseTTCharmap(face, 1, 0); + } + static bool UseTTCharmap(FXFT_FaceRec* face, + int platform_id, + int encoding_id); + + static const char* GetAdobeCharName(FontEncoding base_encoding, const std::vector<ByteString>& charnames, uint32_t charcode); @@ -143,6 +166,7 @@ void CheckFontMetrics(); UnownedPtr<CPDF_Document> const m_pDocument; + ByteString m_ResourceName; // The resource name for this font. CFX_Font m_Font; std::vector<std::unique_ptr<CFX_Font>> m_FontFallbacks; RetainPtr<CPDF_StreamAcc> m_pFontFile;
diff --git a/core/fpdfapi/font/cpdf_fontencoding.cpp b/core/fpdfapi/font/cpdf_fontencoding.cpp index a4e687e..ff2baed 100644 --- a/core/fpdfapi/font/cpdf_fontencoding.cpp +++ b/core/fpdfapi/font/cpdf_fontencoding.cpp
@@ -1,4 +1,4 @@ -// Copyright 2016 PDFium Authors. All rights reserved. +// Copyright 2016 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -6,20 +6,21 @@ #include "core/fpdfapi/font/cpdf_fontencoding.h" -#include <utility> +#include <iterator> +#include "constants/font_encodings.h" #include "core/fpdfapi/parser/cpdf_array.h" #include "core/fpdfapi/parser/cpdf_dictionary.h" #include "core/fpdfapi/parser/cpdf_name.h" #include "core/fpdfapi/parser/cpdf_number.h" #include "core/fpdfapi/parser/fpdf_parser_decode.h" +#include "core/fxge/freetype/fx_freetype.h" #include "core/fxge/fx_font.h" -#include "core/fxge/fx_freetype.h" -#include "third_party/base/ptr_util.h" +#include "third_party/abseil-cpp/absl/types/optional.h" namespace { -const uint16_t MSSymbolEncoding[CPDF_FontEncoding::kEncodingTableSize] = { +const uint16_t kMSSymbolEncoding[CPDF_FontEncoding::kEncodingTableSize] = { 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, @@ -50,7 +51,7 @@ 0x2320, 0x0000, 0x2321, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000}; -const uint16_t StandardEncoding[CPDF_FontEncoding::kEncodingTableSize] = { +const uint16_t kStandardEncoding[CPDF_FontEncoding::kEncodingTableSize] = { 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, @@ -81,7 +82,7 @@ 0x0000, 0x0000, 0x0131, 0x0000, 0x0000, 0x0142, 0x00f8, 0x0153, 0x00df, 0x0000, 0x0000, 0x0000, 0x0000}; -const uint16_t MacRomanEncoding[CPDF_FontEncoding::kEncodingTableSize] = { +const uint16_t kMacRomanEncoding[CPDF_FontEncoding::kEncodingTableSize] = { 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, @@ -112,7 +113,7 @@ 0x00db, 0x00d9, 0x0131, 0x02c6, 0x02dc, 0x00af, 0x02d8, 0x02d9, 0x02da, 0x00b8, 0x02dd, 0x02db, 0x02c7}; -const uint16_t AdobeWinAnsiEncoding[CPDF_FontEncoding::kEncodingTableSize] = { +const uint16_t kAdobeWinAnsiEncoding[CPDF_FontEncoding::kEncodingTableSize] = { 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, @@ -143,7 +144,7 @@ 0x00f3, 0x00f4, 0x00f5, 0x00f6, 0x00f7, 0x00f8, 0x00f9, 0x00fa, 0x00fb, 0x00fc, 0x00fd, 0x00fe, 0x00ff}; -const uint16_t MacExpertEncoding[CPDF_FontEncoding::kEncodingTableSize] = { +const uint16_t kMacExpertEncoding[CPDF_FontEncoding::kEncodingTableSize] = { 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, @@ -174,7 +175,7 @@ 0xf6f4, 0xf7af, 0xf6ea, 0x207f, 0xf6ef, 0xf6e2, 0xf6e8, 0xf6f7, 0xf6fc, 0x0000, 0x0000, 0x0000, 0x0000}; -const uint16_t AdobeSymbolEncoding[CPDF_FontEncoding::kEncodingTableSize] = { +const uint16_t kAdobeSymbolEncoding[CPDF_FontEncoding::kEncodingTableSize] = { 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, @@ -206,7 +207,7 @@ 0xF8FC, 0xF8FD, 0xF8FE, 0x0000, }; -const uint16_t ZapfEncoding[CPDF_FontEncoding::kEncodingTableSize] = { +const uint16_t kZapfEncoding[CPDF_FontEncoding::kEncodingTableSize] = { 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, @@ -245,7 +246,7 @@ constexpr size_t kPDFDocEncodingNamesTableSize = CPDF_FontEncoding::kEncodingTableSize - kPDFDocEncodingTableFirstChar; -const char* const StandardEncodingNames[kEncodingNamesTableSize] = { +const char* const kStandardEncodingNames[kEncodingNamesTableSize] = { "space", "exclam", "quotedbl", @@ -472,7 +473,7 @@ nullptr, }; -const char* const AdobeWinAnsiEncodingNames[kEncodingNamesTableSize] = { +const char* const kAdobeWinAnsiEncodingNames[kEncodingNamesTableSize] = { "space", "exclam", "quotedbl", @@ -699,7 +700,7 @@ "ydieresis", }; -const char* const MacRomanEncodingNames[kEncodingNamesTableSize] = { +const char* const kMacRomanEncodingNames[kEncodingNamesTableSize] = { "space", "exclam", "quotedbl", @@ -926,7 +927,7 @@ "caron", }; -const char* const MacExpertEncodingNames[kEncodingNamesTableSize] = { +const char* const kMacExpertEncodingNames[kEncodingNamesTableSize] = { "space", "exclamsmall", "Hungarumlautsmall", @@ -1153,7 +1154,7 @@ nullptr, }; -const char* const PDFDocEncodingNames[kPDFDocEncodingNamesTableSize] = { +const char* const kPDFDocEncodingNames[kPDFDocEncodingNamesTableSize] = { "breve", "caron", "circumflex", @@ -1388,7 +1389,7 @@ "ydieresis", }; -const char* const AdobeSymbolEncodingNames[kEncodingNamesTableSize] = { +const char* const kAdobeSymbolEncodingNames[kEncodingNamesTableSize] = { "space", "exclam", "universal", @@ -1615,7 +1616,7 @@ nullptr, }; -const char* const ZapfEncodingNames[kEncodingNamesTableSize] = { +const char* const kZapfEncodingNames[kEncodingNamesTableSize] = { "space", "a1", "a2", "a202", "a3", "a4", "a5", "a119", "a118", "a117", "a11", "a12", "a13", "a14", "a15", "a16", "a105", "a17", "a18", "a19", "a20", "a21", "a22", "a23", @@ -1648,7 +1649,7 @@ uint32_t PDF_FindCode(const uint16_t* pCodes, uint16_t unicode) { for (size_t i = 0; i < CPDF_FontEncoding::kEncodingTableSize; i++) { if (pCodes[i] == unicode) - return i; + return static_cast<uint32_t>(i); } return 0; } @@ -1656,20 +1657,18 @@ } // namespace int CPDF_FontEncoding::CharCodeFromUnicode(wchar_t unicode) const { - for (size_t i = 0; i < FX_ArraySize(m_Unicodes); i++) { + for (size_t i = 0; i < std::size(m_Unicodes); i++) { if (m_Unicodes[i] == unicode) - return i; + return static_cast<int>(i); } return -1; } -CPDF_FontEncoding::CPDF_FontEncoding(int PredefinedEncoding) { - const uint16_t* pSrc = PDF_UnicodesForPredefinedCharSet(PredefinedEncoding); +CPDF_FontEncoding::CPDF_FontEncoding(FontEncoding predefined_encoding) { + const uint16_t* pSrc = UnicodesForPredefinedCharSet(predefined_encoding); if (pSrc) { - for (size_t i = 0; i < FX_ArraySize(m_Unicodes); i++) + for (size_t i = 0; i < std::size(m_Unicodes); i++) m_Unicodes[i] = pSrc[i]; - } else { - memset(m_Unicodes, 0, sizeof(m_Unicodes)); } } @@ -1679,12 +1678,17 @@ RetainPtr<CPDF_Object> CPDF_FontEncoding::Realize( WeakPtr<ByteStringPool> pPool) const { - int predefined = 0; - for (int cs = PDFFONT_ENCODING_WINANSI; cs < PDFFONT_ENCODING_ZAPFDINGBATS; - cs++) { - const uint16_t* pSrc = PDF_UnicodesForPredefinedCharSet(cs); + static constexpr FontEncoding kEncodings[] = { + FontEncoding::kWinAnsi, FontEncoding::kMacRoman, + FontEncoding::kMacExpert, FontEncoding::kStandard, + FontEncoding::kAdobeSymbol, + }; + + absl::optional<FontEncoding> predefined; + for (FontEncoding cs : kEncodings) { + const uint16_t* pSrc = UnicodesForPredefinedCharSet(cs); bool match = true; - for (size_t i = 0; i < FX_ArraySize(m_Unicodes); i++) { + for (size_t i = 0; i < std::size(m_Unicodes); i++) { if (m_Unicodes[i] != pSrc[i]) { match = false; break; @@ -1695,79 +1699,87 @@ break; } } - if (predefined) { + if (predefined.has_value()) { const char* pName; - if (predefined == PDFFONT_ENCODING_WINANSI) - pName = "WinAnsiEncoding"; - else if (predefined == PDFFONT_ENCODING_MACROMAN) - pName = "MacRomanEncoding"; - else if (predefined == PDFFONT_ENCODING_MACEXPERT) - pName = "MacExpertEncoding"; + if (predefined.value() == FontEncoding::kWinAnsi) + pName = pdfium::font_encodings::kWinAnsiEncoding; + else if (predefined.value() == FontEncoding::kMacRoman) + pName = pdfium::font_encodings::kMacRomanEncoding; + else if (predefined.value() == FontEncoding::kMacExpert) + pName = pdfium::font_encodings::kMacExpertEncoding; else return nullptr; return pdfium::MakeRetain<CPDF_Name>(pPool, pName); } const uint16_t* pStandard = - PDF_UnicodesForPredefinedCharSet(PDFFONT_ENCODING_WINANSI); + UnicodesForPredefinedCharSet(FontEncoding::kWinAnsi); auto pDiff = pdfium::MakeRetain<CPDF_Array>(); - for (size_t i = 0; i < FX_ArraySize(m_Unicodes); i++) { + for (size_t i = 0; i < std::size(m_Unicodes); i++) { if (pStandard[i] == m_Unicodes[i]) continue; - pDiff->AddNew<CPDF_Number>(static_cast<int>(i)); - pDiff->AddNew<CPDF_Name>(PDF_AdobeNameFromUnicode(m_Unicodes[i])); + pDiff->AppendNew<CPDF_Number>(static_cast<int>(i)); + pDiff->AppendNew<CPDF_Name>(AdobeNameFromUnicode(m_Unicodes[i])); } auto pDict = pdfium::MakeRetain<CPDF_Dictionary>(pPool); - pDict->SetNewFor<CPDF_Name>("BaseEncoding", "WinAnsiEncoding"); + pDict->SetNewFor<CPDF_Name>("BaseEncoding", + pdfium::font_encodings::kWinAnsiEncoding); pDict->SetFor("Differences", pDiff); return pDict; } -uint32_t FT_CharCodeFromUnicode(int encoding, wchar_t unicode) { +uint32_t CharCodeFromUnicodeForFreetypeEncoding(int encoding, wchar_t unicode) { switch (encoding) { case FT_ENCODING_UNICODE: return unicode; case FT_ENCODING_ADOBE_STANDARD: - return PDF_FindCode(StandardEncoding, unicode); + return PDF_FindCode(kStandardEncoding, unicode); case FT_ENCODING_ADOBE_EXPERT: - return PDF_FindCode(MacExpertEncoding, unicode); + return PDF_FindCode(kMacExpertEncoding, unicode); case FT_ENCODING_ADOBE_LATIN_1: - return PDF_FindCode(AdobeWinAnsiEncoding, unicode); + return PDF_FindCode(kAdobeWinAnsiEncoding, unicode); case FT_ENCODING_APPLE_ROMAN: - return PDF_FindCode(MacRomanEncoding, unicode); + return PDF_FindCode(kMacRomanEncoding, unicode); case FT_ENCODING_ADOBE_CUSTOM: - return PDF_FindCode(PDFDocEncoding, unicode); + return PDF_FindCode(kPDFDocEncoding, unicode); case FT_ENCODING_MS_SYMBOL: - return PDF_FindCode(MSSymbolEncoding, unicode); + return PDF_FindCode(kMSSymbolEncoding, unicode); } return 0; } -const uint16_t* PDF_UnicodesForPredefinedCharSet(int encoding) { - switch (encoding) { - case PDFFONT_ENCODING_WINANSI: - return AdobeWinAnsiEncoding; - case PDFFONT_ENCODING_MACROMAN: - return MacRomanEncoding; - case PDFFONT_ENCODING_MACEXPERT: - return MacExpertEncoding; - case PDFFONT_ENCODING_STANDARD: - return StandardEncoding; - case PDFFONT_ENCODING_ADOBE_SYMBOL: - return AdobeSymbolEncoding; - case PDFFONT_ENCODING_ZAPFDINGBATS: - return ZapfEncoding; - case PDFFONT_ENCODING_PDFDOC: - return PDFDocEncoding; - case PDFFONT_ENCODING_MS_SYMBOL: - return MSSymbolEncoding; - } - return nullptr; + +wchar_t UnicodeFromAppleRomanCharCode(uint8_t charcode) { + return kMacRomanEncoding[charcode]; } -const char* PDF_CharNameFromPredefinedCharSet(int encoding, uint8_t charcode) { - if (encoding == PDFFONT_ENCODING_PDFDOC) { +const uint16_t* UnicodesForPredefinedCharSet(FontEncoding encoding) { + switch (encoding) { + case FontEncoding::kBuiltin: + return nullptr; + case FontEncoding::kWinAnsi: + return kAdobeWinAnsiEncoding; + case FontEncoding::kMacRoman: + return kMacRomanEncoding; + case FontEncoding::kMacExpert: + return kMacExpertEncoding; + case FontEncoding::kStandard: + return kStandardEncoding; + case FontEncoding::kAdobeSymbol: + return kAdobeSymbolEncoding; + case FontEncoding::kZapfDingbats: + return kZapfEncoding; + case FontEncoding::kPdfDoc: + return kPDFDocEncoding; + case FontEncoding::kMsSymbol: + return kMSSymbolEncoding; + } +} + +const char* CharNameFromPredefinedCharSet(FontEncoding encoding, + uint8_t charcode) { + if (encoding == FontEncoding::kPdfDoc) { if (charcode < kPDFDocEncodingTableFirstChar) return nullptr; @@ -1779,38 +1791,21 @@ charcode -= kEncodingTableFirstChar; } switch (encoding) { - case PDFFONT_ENCODING_WINANSI: - return AdobeWinAnsiEncodingNames[charcode]; - case PDFFONT_ENCODING_MACROMAN: - return MacRomanEncodingNames[charcode]; - case PDFFONT_ENCODING_MACEXPERT: - return MacExpertEncodingNames[charcode]; - case PDFFONT_ENCODING_STANDARD: - return StandardEncodingNames[charcode]; - case PDFFONT_ENCODING_ADOBE_SYMBOL: - return AdobeSymbolEncodingNames[charcode]; - case PDFFONT_ENCODING_ZAPFDINGBATS: - return ZapfEncodingNames[charcode]; - case PDFFONT_ENCODING_PDFDOC: - return PDFDocEncodingNames[charcode]; + case FontEncoding::kWinAnsi: + return kAdobeWinAnsiEncodingNames[charcode]; + case FontEncoding::kMacRoman: + return kMacRomanEncodingNames[charcode]; + case FontEncoding::kMacExpert: + return kMacExpertEncodingNames[charcode]; + case FontEncoding::kStandard: + return kStandardEncodingNames[charcode]; + case FontEncoding::kAdobeSymbol: + return kAdobeSymbolEncodingNames[charcode]; + case FontEncoding::kZapfDingbats: + return kZapfEncodingNames[charcode]; + case FontEncoding::kPdfDoc: + return kPDFDocEncodingNames[charcode]; + default: + return nullptr; } - return nullptr; -} - -wchar_t FT_UnicodeFromCharCode(int encoding, uint32_t charcode) { - switch (encoding) { - case FT_ENCODING_UNICODE: - return (uint16_t)charcode; - case FT_ENCODING_ADOBE_STANDARD: - return StandardEncoding[(uint8_t)charcode]; - case FT_ENCODING_ADOBE_EXPERT: - return MacExpertEncoding[(uint8_t)charcode]; - case FT_ENCODING_ADOBE_LATIN_1: - return AdobeWinAnsiEncoding[(uint8_t)charcode]; - case FT_ENCODING_APPLE_ROMAN: - return MacRomanEncoding[(uint8_t)charcode]; - case PDFFONT_ENCODING_PDFDOC: - return PDFDocEncoding[(uint8_t)charcode]; - } - return 0; }
diff --git a/core/fpdfapi/font/cpdf_fontencoding.h b/core/fpdfapi/font/cpdf_fontencoding.h index 1bfb0d5..272c8a6 100644 --- a/core/fpdfapi/font/cpdf_fontencoding.h +++ b/core/fpdfapi/font/cpdf_fontencoding.h
@@ -1,4 +1,4 @@ -// Copyright 2016 PDFium Authors. All rights reserved. +// Copyright 2016 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -7,27 +7,29 @@ #ifndef CORE_FPDFAPI_FONT_CPDF_FONTENCODING_H_ #define CORE_FPDFAPI_FONT_CPDF_FONTENCODING_H_ -#include <memory> - -#include "core/fxcrt/fx_string.h" +#include "core/fxcrt/bytestring.h" +#include "core/fxcrt/retain_ptr.h" #include "core/fxcrt/string_pool_template.h" #include "core/fxcrt/weak_ptr.h" -#define PDFFONT_ENCODING_BUILTIN 0 -#define PDFFONT_ENCODING_WINANSI 1 -#define PDFFONT_ENCODING_MACROMAN 2 -#define PDFFONT_ENCODING_MACEXPERT 3 -#define PDFFONT_ENCODING_STANDARD 4 -#define PDFFONT_ENCODING_ADOBE_SYMBOL 5 -#define PDFFONT_ENCODING_ZAPFDINGBATS 6 -#define PDFFONT_ENCODING_PDFDOC 7 -#define PDFFONT_ENCODING_MS_SYMBOL 8 +enum class FontEncoding { + kBuiltin = 0, + kWinAnsi = 1, + kMacRoman = 2, + kMacExpert = 3, + kStandard = 4, + kAdobeSymbol = 5, + kZapfDingbats = 6, + kPdfDoc = 7, + kMsSymbol = 8, +}; -uint32_t FT_CharCodeFromUnicode(int encoding, wchar_t unicode); -wchar_t FT_UnicodeFromCharCode(int encoding, uint32_t charcode); +uint32_t CharCodeFromUnicodeForFreetypeEncoding(int encoding, wchar_t unicode); +wchar_t UnicodeFromAppleRomanCharCode(uint8_t charcode); -const uint16_t* PDF_UnicodesForPredefinedCharSet(int encoding); -const char* PDF_CharNameFromPredefinedCharSet(int encoding, uint8_t charcode); +const uint16_t* UnicodesForPredefinedCharSet(FontEncoding encoding); +const char* CharNameFromPredefinedCharSet(FontEncoding encoding, + uint8_t charcode); class CPDF_Object; @@ -35,7 +37,7 @@ public: static constexpr size_t kEncodingTableSize = 256; - explicit CPDF_FontEncoding(int PredefinedEncoding); + explicit CPDF_FontEncoding(FontEncoding predefined_encoding); bool IsIdentical(const CPDF_FontEncoding* pAnother) const; @@ -51,7 +53,7 @@ RetainPtr<CPDF_Object> Realize(WeakPtr<ByteStringPool> pPool) const; private: - wchar_t m_Unicodes[kEncodingTableSize]; + wchar_t m_Unicodes[kEncodingTableSize] = {}; }; #endif // CORE_FPDFAPI_FONT_CPDF_FONTENCODING_H_
diff --git a/core/fpdfapi/font/cpdf_fontglobals.cpp b/core/fpdfapi/font/cpdf_fontglobals.cpp index 10b6c5e..1aa19d6 100644 --- a/core/fpdfapi/font/cpdf_fontglobals.cpp +++ b/core/fpdfapi/font/cpdf_fontglobals.cpp
@@ -1,4 +1,4 @@ -// Copyright 2017 PDFium Authors. All rights reserved. +// Copyright 2017 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -6,37 +6,47 @@ #include "core/fpdfapi/font/cpdf_fontglobals.h" +#include <utility> + #include "core/fpdfapi/cmaps/CNS1/cmaps_cns1.h" #include "core/fpdfapi/cmaps/GB1/cmaps_gb1.h" #include "core/fpdfapi/cmaps/Japan1/cmaps_japan1.h" #include "core/fpdfapi/cmaps/Korea1/cmaps_korea1.h" #include "core/fpdfapi/font/cfx_stockfontarray.h" +#include "core/fpdfapi/font/cpdf_cid2unicodemap.h" +#include "core/fpdfapi/font/cpdf_cmap.h" #include "core/fpdfapi/parser/cpdf_document.h" -#include "third_party/base/ptr_util.h" -#include "third_party/base/stl_util.h" +#include "third_party/base/check.h" +#include "third_party/base/containers/contains.h" namespace { CPDF_FontGlobals* g_FontGlobals = nullptr; +RetainPtr<const CPDF_CMap> LoadPredefinedCMap(ByteStringView name) { + if (!name.IsEmpty() && name[0] == '/') + name = name.Last(name.GetLength() - 1); + return pdfium::MakeRetain<CPDF_CMap>(name); +} + } // namespace // static void CPDF_FontGlobals::Create() { - ASSERT(!g_FontGlobals); + DCHECK(!g_FontGlobals); g_FontGlobals = new CPDF_FontGlobals(); } // static void CPDF_FontGlobals::Destroy() { - ASSERT(g_FontGlobals); + DCHECK(g_FontGlobals); delete g_FontGlobals; g_FontGlobals = nullptr; } // static CPDF_FontGlobals* CPDF_FontGlobals::GetInstance() { - ASSERT(g_FontGlobals); + DCHECK(g_FontGlobals); return g_FontGlobals; } @@ -66,38 +76,63 @@ void CPDF_FontGlobals::Set(CPDF_Document* pDoc, CFX_FontMapper::StandardFont index, - const RetainPtr<CPDF_Font>& pFont) { - if (!pdfium::ContainsKey(m_StockMap, pDoc)) - m_StockMap[pDoc] = pdfium::MakeUnique<CFX_StockFontArray>(); - m_StockMap[pDoc]->SetFont(index, pFont); + RetainPtr<CPDF_Font> pFont) { + UnownedPtr<CPDF_Document> pKey(pDoc); + if (!pdfium::Contains(m_StockMap, pKey)) + m_StockMap[pKey] = std::make_unique<CFX_StockFontArray>(); + m_StockMap[pKey]->SetFont(index, std::move(pFont)); } void CPDF_FontGlobals::Clear(CPDF_Document* pDoc) { - m_StockMap.erase(pDoc); + // Avoid constructing smart-pointer key as erase() doesn't invoke + // transparent lookup in the same way find() does. + auto it = m_StockMap.find(pDoc); + if (it != m_StockMap.end()) + m_StockMap.erase(it); } void CPDF_FontGlobals::LoadEmbeddedGB1CMaps() { - SetEmbeddedCharset(CIDSET_GB1, pdfium::make_span(g_FXCMAP_GB1_cmaps, - g_FXCMAP_GB1_cmaps_size)); - SetEmbeddedToUnicode(CIDSET_GB1, g_FXCMAP_GB1CID2Unicode_5); + SetEmbeddedCharset(CIDSET_GB1, pdfium::make_span(fxcmap::kGB1_cmaps, + fxcmap::kGB1_cmaps_size)); + SetEmbeddedToUnicode(CIDSET_GB1, fxcmap::kGB1CID2Unicode_5); } void CPDF_FontGlobals::LoadEmbeddedCNS1CMaps() { - SetEmbeddedCharset(CIDSET_CNS1, pdfium::make_span(g_FXCMAP_CNS1_cmaps, - g_FXCMAP_CNS1_cmaps_size)); - SetEmbeddedToUnicode(CIDSET_CNS1, g_FXCMAP_CNS1CID2Unicode_5); + SetEmbeddedCharset(CIDSET_CNS1, pdfium::make_span(fxcmap::kCNS1_cmaps, + fxcmap::kCNS1_cmaps_size)); + SetEmbeddedToUnicode(CIDSET_CNS1, fxcmap::kCNS1CID2Unicode_5); } void CPDF_FontGlobals::LoadEmbeddedJapan1CMaps() { SetEmbeddedCharset( CIDSET_JAPAN1, - pdfium::make_span(g_FXCMAP_Japan1_cmaps, g_FXCMAP_Japan1_cmaps_size)); - SetEmbeddedToUnicode(CIDSET_JAPAN1, g_FXCMAP_Japan1CID2Unicode_4); + pdfium::make_span(fxcmap::kJapan1_cmaps, fxcmap::kJapan1_cmaps_size)); + SetEmbeddedToUnicode(CIDSET_JAPAN1, fxcmap::kJapan1CID2Unicode_4); } void CPDF_FontGlobals::LoadEmbeddedKorea1CMaps() { SetEmbeddedCharset( CIDSET_KOREA1, - pdfium::make_span(g_FXCMAP_Korea1_cmaps, g_FXCMAP_Korea1_cmaps_size)); - SetEmbeddedToUnicode(CIDSET_KOREA1, g_FXCMAP_Korea1CID2Unicode_2); + pdfium::make_span(fxcmap::kKorea1_cmaps, fxcmap::kKorea1_cmaps_size)); + SetEmbeddedToUnicode(CIDSET_KOREA1, fxcmap::kKorea1CID2Unicode_2); +} + +RetainPtr<const CPDF_CMap> CPDF_FontGlobals::GetPredefinedCMap( + const ByteString& name) { + auto it = m_CMaps.find(name); + if (it != m_CMaps.end()) + return it->second; + + RetainPtr<const CPDF_CMap> pCMap = LoadPredefinedCMap(name.AsStringView()); + if (!name.IsEmpty()) + m_CMaps[name] = pCMap; + + return pCMap; +} + +CPDF_CID2UnicodeMap* CPDF_FontGlobals::GetCID2UnicodeMap(CIDSet charset) { + if (!m_CID2UnicodeMaps[charset]) { + m_CID2UnicodeMaps[charset] = std::make_unique<CPDF_CID2UnicodeMap>(charset); + } + return m_CID2UnicodeMaps[charset].get(); }
diff --git a/core/fpdfapi/font/cpdf_fontglobals.h b/core/fpdfapi/font/cpdf_fontglobals.h index c09f29c..6b2e3bc 100644 --- a/core/fpdfapi/font/cpdf_fontglobals.h +++ b/core/fpdfapi/font/cpdf_fontglobals.h
@@ -1,4 +1,4 @@ -// Copyright 2017 PDFium Authors. All rights reserved. +// Copyright 2017 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -7,16 +7,18 @@ #ifndef CORE_FPDFAPI_FONT_CPDF_FONTGLOBALS_H_ #define CORE_FPDFAPI_FONT_CPDF_FONTGLOBALS_H_ +#include <functional> #include <map> #include <memory> #include "core/fpdfapi/cmaps/fpdf_cmaps.h" -#include "core/fpdfapi/font/cpdf_cmapmanager.h" +#include "core/fpdfapi/font/cpdf_cidfont.h" #include "core/fxcrt/retain_ptr.h" #include "core/fxge/cfx_fontmapper.h" #include "third_party/base/span.h" class CFX_StockFontArray; +class CPDF_Font; class CPDF_FontGlobals { public: @@ -33,22 +35,23 @@ CFX_FontMapper::StandardFont index); void Set(CPDF_Document* pDoc, CFX_FontMapper::StandardFont index, - const RetainPtr<CPDF_Font>& pFont); + RetainPtr<CPDF_Font> pFont); - void SetEmbeddedCharset(size_t idx, pdfium::span<const FXCMAP_CMap> map) { + void SetEmbeddedCharset(CIDSet idx, pdfium::span<const fxcmap::CMap> map) { m_EmbeddedCharsets[idx] = map; } - pdfium::span<const FXCMAP_CMap> GetEmbeddedCharset(size_t idx) const { + pdfium::span<const fxcmap::CMap> GetEmbeddedCharset(CIDSet idx) const { return m_EmbeddedCharsets[idx]; } - void SetEmbeddedToUnicode(size_t idx, pdfium::span<const uint16_t> map) { + void SetEmbeddedToUnicode(CIDSet idx, pdfium::span<const uint16_t> map) { m_EmbeddedToUnicodes[idx] = map; } - pdfium::span<const uint16_t> GetEmbeddedToUnicode(size_t idx) { + pdfium::span<const uint16_t> GetEmbeddedToUnicode(CIDSet idx) { return m_EmbeddedToUnicodes[idx]; } - CPDF_CMapManager* GetCMapManager() { return &m_CMapManager; } + RetainPtr<const CPDF_CMap> GetPredefinedCMap(const ByteString& name); + CPDF_CID2UnicodeMap* GetCID2UnicodeMap(CIDSet charset); private: CPDF_FontGlobals(); @@ -59,10 +62,14 @@ void LoadEmbeddedJapan1CMaps(); void LoadEmbeddedKorea1CMaps(); - CPDF_CMapManager m_CMapManager; - pdfium::span<const FXCMAP_CMap> m_EmbeddedCharsets[CIDSET_NUM_SETS]; + std::map<ByteString, RetainPtr<const CPDF_CMap>> m_CMaps; + std::unique_ptr<CPDF_CID2UnicodeMap> m_CID2UnicodeMaps[CIDSET_NUM_SETS]; + pdfium::span<const fxcmap::CMap> m_EmbeddedCharsets[CIDSET_NUM_SETS]; pdfium::span<const uint16_t> m_EmbeddedToUnicodes[CIDSET_NUM_SETS]; - std::map<CPDF_Document*, std::unique_ptr<CFX_StockFontArray>> m_StockMap; + std::map<UnownedPtr<CPDF_Document>, + std::unique_ptr<CFX_StockFontArray>, + std::less<>> + m_StockMap; }; #endif // CORE_FPDFAPI_FONT_CPDF_FONTGLOBALS_H_
diff --git a/core/fpdfapi/font/cpdf_simplefont.cpp b/core/fpdfapi/font/cpdf_simplefont.cpp index c0fd4e0..ecdf72a 100644 --- a/core/fpdfapi/font/cpdf_simplefont.cpp +++ b/core/fpdfapi/font/cpdf_simplefont.cpp
@@ -1,4 +1,4 @@ -// Copyright 2016 PDFium Authors. All rights reserved. +// Copyright 2016 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -6,34 +6,40 @@ #include "core/fpdfapi/font/cpdf_simplefont.h" +#include <algorithm> +#include <iterator> +#include <utility> + +#include "constants/font_encodings.h" #include "core/fpdfapi/parser/cpdf_array.h" #include "core/fpdfapi/parser/cpdf_dictionary.h" #include "core/fpdfapi/parser/cpdf_name.h" +#include "core/fxcrt/fx_codepage.h" +#include "core/fxge/freetype/fx_freetype.h" #include "core/fxge/fx_font.h" -#include "core/fxge/fx_freetype.h" #include "third_party/base/numerics/safe_math.h" namespace { -void GetPredefinedEncoding(const ByteString& value, int* basemap) { - if (value == "WinAnsiEncoding") - *basemap = PDFFONT_ENCODING_WINANSI; - else if (value == "MacRomanEncoding") - *basemap = PDFFONT_ENCODING_MACROMAN; - else if (value == "MacExpertEncoding") - *basemap = PDFFONT_ENCODING_MACEXPERT; - else if (value == "PDFDocEncoding") - *basemap = PDFFONT_ENCODING_PDFDOC; +void GetPredefinedEncoding(const ByteString& value, FontEncoding* basemap) { + if (value == pdfium::font_encodings::kWinAnsiEncoding) + *basemap = FontEncoding::kWinAnsi; + else if (value == pdfium::font_encodings::kMacRomanEncoding) + *basemap = FontEncoding::kMacRoman; + else if (value == pdfium::font_encodings::kMacExpertEncoding) + *basemap = FontEncoding::kMacExpert; + else if (value == pdfium::font_encodings::kPDFDocEncoding) + *basemap = FontEncoding::kPdfDoc; } } // namespace CPDF_SimpleFont::CPDF_SimpleFont(CPDF_Document* pDocument, - CPDF_Dictionary* pFontDict) - : CPDF_Font(pDocument, pFontDict) { + RetainPtr<CPDF_Dictionary> pFontDict) + : CPDF_Font(pDocument, std::move(pFontDict)) { memset(m_CharWidth, 0xff, sizeof(m_CharWidth)); memset(m_GlyphIndex, 0xff, sizeof(m_GlyphIndex)); - for (size_t i = 0; i < FX_ArraySize(m_CharBBox); ++i) + for (size_t i = 0; i < std::size(m_CharBBox); ++i) m_CharBBox[i] = FX_RECT(-1, -1, -1, -1); } @@ -78,8 +84,8 @@ if (err) return; - int iHoriBearingX = FXFT_Get_Glyph_HoriBearingX(face); - int iHoriBearingY = FXFT_Get_Glyph_HoriBearingY(face); + FT_Pos iHoriBearingX = FXFT_Get_Glyph_HoriBearingX(face); + FT_Pos iHoriBearingY = FXFT_Get_Glyph_HoriBearingY(face); m_CharBBox[charcode] = FX_RECT(TT2PDF(iHoriBearingX, face), TT2PDF(iHoriBearingY, face), TT2PDF(iHoriBearingX + FXFT_Get_Glyph_Width(face), face), @@ -98,31 +104,78 @@ } } +void CPDF_SimpleFont::LoadCharWidths(const CPDF_Dictionary* font_desc) { + RetainPtr<const CPDF_Array> width_array = m_pFontDict->GetArrayFor("Widths"); + m_bUseFontWidth = !width_array; + if (!width_array) + return; + + if (font_desc && font_desc->KeyExist("MissingWidth")) { + int missing_width = font_desc->GetIntegerFor("MissingWidth"); + std::fill(std::begin(m_CharWidth), std::end(m_CharWidth), missing_width); + } + + size_t width_start = m_pFontDict->GetIntegerFor("FirstChar", 0); + size_t width_end = m_pFontDict->GetIntegerFor("LastChar", 0); + if (width_start > 255) + return; + + if (width_end == 0 || width_end >= width_start + width_array->size()) + width_end = width_start + width_array->size() - 1; + if (width_end > 255) + width_end = 255; + for (size_t i = width_start; i <= width_end; i++) + m_CharWidth[i] = width_array->GetIntegerAt(i - width_start); +} + +void CPDF_SimpleFont::LoadDifferences(const CPDF_Dictionary* encoding) { + RetainPtr<const CPDF_Array> diffs = encoding->GetArrayFor("Differences"); + if (!diffs) + return; + + m_CharNames.resize(kInternalTableSize); + uint32_t cur_code = 0; + for (uint32_t i = 0; i < diffs->size(); i++) { + RetainPtr<const CPDF_Object> element = diffs->GetDirectObjectAt(i); + if (!element) + continue; + + const CPDF_Name* name = element->AsName(); + if (name) { + if (cur_code < m_CharNames.size()) + m_CharNames[cur_code] = name->GetString(); + cur_code++; + } else { + cur_code = element->GetInteger(); + } + } +} + void CPDF_SimpleFont::LoadPDFEncoding(bool bEmbedded, bool bTrueType) { - const CPDF_Object* pEncoding = m_pFontDict->GetDirectObjectFor("Encoding"); + RetainPtr<const CPDF_Object> pEncoding = + m_pFontDict->GetDirectObjectFor("Encoding"); if (!pEncoding) { if (m_BaseFontName == "Symbol") { - m_BaseEncoding = bTrueType ? PDFFONT_ENCODING_MS_SYMBOL - : PDFFONT_ENCODING_ADOBE_SYMBOL; - } else if (!bEmbedded && m_BaseEncoding == PDFFONT_ENCODING_BUILTIN) { - m_BaseEncoding = PDFFONT_ENCODING_WINANSI; + m_BaseEncoding = + bTrueType ? FontEncoding::kMsSymbol : FontEncoding::kAdobeSymbol; + } else if (!bEmbedded && m_BaseEncoding == FontEncoding::kBuiltin) { + m_BaseEncoding = FontEncoding::kWinAnsi; } return; } if (pEncoding->IsName()) { - if (m_BaseEncoding == PDFFONT_ENCODING_ADOBE_SYMBOL || - m_BaseEncoding == PDFFONT_ENCODING_ZAPFDINGBATS) { + if (m_BaseEncoding == FontEncoding::kAdobeSymbol || + m_BaseEncoding == FontEncoding::kZapfDingbats) { return; } if (FontStyleIsSymbolic(m_Flags) && m_BaseFontName == "Symbol") { if (!bTrueType) - m_BaseEncoding = PDFFONT_ENCODING_ADOBE_SYMBOL; + m_BaseEncoding = FontEncoding::kAdobeSymbol; return; } ByteString bsEncoding = pEncoding->GetString(); - if (bsEncoding.Compare("MacExpertEncoding") == 0) { - bsEncoding = "WinAnsiEncoding"; - } + if (bsEncoding == pdfium::font_encodings::kMacExpertEncoding) + bsEncoding = pdfium::font_encodings::kWinAnsiEncoding; GetPredefinedEncoding(bsEncoding, &m_BaseEncoding); return; } @@ -131,39 +184,20 @@ if (!pDict) return; - if (m_BaseEncoding != PDFFONT_ENCODING_ADOBE_SYMBOL && - m_BaseEncoding != PDFFONT_ENCODING_ZAPFDINGBATS) { - ByteString bsEncoding = pDict->GetStringFor("BaseEncoding"); - if (bTrueType && bsEncoding.Compare("MacExpertEncoding") == 0) - bsEncoding = "WinAnsiEncoding"; + if (m_BaseEncoding != FontEncoding::kAdobeSymbol && + m_BaseEncoding != FontEncoding::kZapfDingbats) { + ByteString bsEncoding = pDict->GetByteStringFor("BaseEncoding"); + if (bTrueType && bsEncoding == pdfium::font_encodings::kMacExpertEncoding) + bsEncoding = pdfium::font_encodings::kWinAnsiEncoding; GetPredefinedEncoding(bsEncoding, &m_BaseEncoding); } - if ((!bEmbedded || bTrueType) && m_BaseEncoding == PDFFONT_ENCODING_BUILTIN) - m_BaseEncoding = PDFFONT_ENCODING_STANDARD; + if ((!bEmbedded || bTrueType) && m_BaseEncoding == FontEncoding::kBuiltin) + m_BaseEncoding = FontEncoding::kStandard; - const CPDF_Array* pDiffs = pDict->GetArrayFor("Differences"); - if (!pDiffs) - return; - - m_CharNames.resize(256); - uint32_t cur_code = 0; - for (uint32_t i = 0; i < pDiffs->size(); i++) { - const CPDF_Object* pElement = pDiffs->GetDirectObjectAt(i); - if (!pElement) - continue; - - const CPDF_Name* pName = pElement->AsName(); - if (pName) { - if (cur_code < 256) - m_CharNames[cur_code] = pName->GetString(); - cur_code++; - } else { - cur_code = pElement->GetInteger(); - } - } + LoadDifferences(pDict); } -uint32_t CPDF_SimpleFont::GetCharWidthF(uint32_t charcode) { +int CPDF_SimpleFont::GetCharWidthF(uint32_t charcode) { if (charcode > 0xff) charcode = 0; @@ -187,30 +221,11 @@ } bool CPDF_SimpleFont::LoadCommon() { - const CPDF_Dictionary* pFontDesc = m_pFontDict->GetDictFor("FontDescriptor"); - if (pFontDesc) { - LoadFontDescriptor(pFontDesc); - } - const CPDF_Array* pWidthArray = m_pFontDict->GetArrayFor("Widths"); - m_bUseFontWidth = !pWidthArray; - if (pWidthArray) { - if (pFontDesc && pFontDesc->KeyExist("MissingWidth")) { - int MissingWidth = pFontDesc->GetIntegerFor("MissingWidth"); - for (int i = 0; i < 256; i++) { - m_CharWidth[i] = MissingWidth; - } - } - size_t width_start = m_pFontDict->GetIntegerFor("FirstChar", 0); - size_t width_end = m_pFontDict->GetIntegerFor("LastChar", 0); - if (width_start <= 255) { - if (width_end == 0 || width_end >= width_start + pWidthArray->size()) - width_end = width_start + pWidthArray->size() - 1; - if (width_end > 255) - width_end = 255; - for (size_t i = width_start; i <= width_end; i++) - m_CharWidth[i] = pWidthArray->GetIntegerAt(i - width_start); - } - } + RetainPtr<const CPDF_Dictionary> pFontDesc = + m_pFontDict->GetDictFor("FontDescriptor"); + if (pFontDesc) + LoadFontDescriptor(pFontDesc.Get()); + LoadCharWidths(pFontDesc.Get()); if (m_pFontFile) { if (m_BaseFontName.GetLength() > 8 && m_BaseFontName[7] == '+') m_BaseFontName = m_BaseFontName.Last(m_BaseFontName.GetLength() - 8); @@ -218,7 +233,7 @@ LoadSubstFont(); } if (!FontStyleIsSymbolic(m_Flags)) - m_BaseEncoding = PDFFONT_ENCODING_STANDARD; + m_BaseEncoding = FontEncoding::kStandard; LoadPDFEncoding(!!m_pFontFile, m_Font.IsTTFont()); LoadGlyphMap(); m_CharNames.clear(); @@ -228,7 +243,7 @@ if (FontStyleIsAllCaps(m_Flags)) { static const unsigned char kLowercases[][2] = { {'a', 'z'}, {0xe0, 0xf6}, {0xf8, 0xfd}}; - for (size_t range = 0; range < FX_ArraySize(kLowercases); ++range) { + for (size_t range = 0; range < std::size(kLowercases); ++range) { const auto& lower = kLowercases[range]; for (int i = lower[0]; i <= lower[1]; ++i) { if (m_GlyphIndex[i] != 0xffff && m_pFontFile) @@ -249,8 +264,9 @@ void CPDF_SimpleFont::LoadSubstFont() { if (!m_bUseFontWidth && !FontStyleIsFixedPitch(m_Flags)) { - int width = 0, i; - for (i = 0; i < 256; i++) { + int width = 0; + size_t i; + for (i = 0; i < kInternalTableSize; i++) { if (m_CharWidth[i] == 0 || m_CharWidth[i] == 0xffff) continue; @@ -259,17 +275,17 @@ else if (width != m_CharWidth[i]) break; } - if (i == 256 && width) + if (i == kInternalTableSize && width) m_Flags |= FXFONT_FIXED_PITCH; } m_Font.LoadSubst(m_BaseFontName, IsTrueTypeFont(), m_Flags, GetFontWeight(), - m_ItalicAngle, 0, false); + m_ItalicAngle, FX_CodePage::kDefANSI, false); } bool CPDF_SimpleFont::IsUnicodeCompatible() const { - return m_BaseEncoding != PDFFONT_ENCODING_BUILTIN && - m_BaseEncoding != PDFFONT_ENCODING_ADOBE_SYMBOL && - m_BaseEncoding != PDFFONT_ENCODING_ZAPFDINGBATS; + return m_BaseEncoding != FontEncoding::kBuiltin && + m_BaseEncoding != FontEncoding::kAdobeSymbol && + m_BaseEncoding != FontEncoding::kZapfDingbats; } WideString CPDF_SimpleFont::UnicodeFromCharCode(uint32_t charcode) const { @@ -279,7 +295,7 @@ wchar_t ret = m_Encoding.UnicodeFromCharCode((uint8_t)charcode); if (ret == 0) return WideString(); - return ret; + return WideString(ret); } uint32_t CPDF_SimpleFont::CharCodeFromUnicode(wchar_t unicode) const {
diff --git a/core/fpdfapi/font/cpdf_simplefont.h b/core/fpdfapi/font/cpdf_simplefont.h index 11359c3..e0d0400 100644 --- a/core/fpdfapi/font/cpdf_simplefont.h +++ b/core/fpdfapi/font/cpdf_simplefont.h
@@ -1,4 +1,4 @@ -// Copyright 2016 PDFium Authors. All rights reserved. +// Copyright 2016 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -7,19 +7,20 @@ #ifndef CORE_FPDFAPI_FONT_CPDF_SIMPLEFONT_H_ #define CORE_FPDFAPI_FONT_CPDF_SIMPLEFONT_H_ +#include <stdint.h> + #include <vector> #include "core/fpdfapi/font/cpdf_font.h" #include "core/fpdfapi/font/cpdf_fontencoding.h" #include "core/fxcrt/fx_string.h" -#include "core/fxcrt/fx_system.h" class CPDF_SimpleFont : public CPDF_Font { public: ~CPDF_SimpleFont() override; // CPDF_Font - uint32_t GetCharWidthF(uint32_t charcode) override; + int GetCharWidthF(uint32_t charcode) override; FX_RECT GetCharBBox(uint32_t charcode) override; int GlyphFromCharCode(uint32_t charcode, bool* pVertGlyph) override; bool IsUnicodeCompatible() const override; @@ -31,22 +32,27 @@ bool HasFontWidths() const override; protected: - CPDF_SimpleFont(CPDF_Document* pDocument, CPDF_Dictionary* pFontDict); + static constexpr size_t kInternalTableSize = 256; + + CPDF_SimpleFont(CPDF_Document* pDocument, + RetainPtr<CPDF_Dictionary> pFontDict); virtual void LoadGlyphMap() = 0; bool LoadCommon(); void LoadSubstFont(); void LoadCharMetrics(int charcode); + void LoadCharWidths(const CPDF_Dictionary* font_desc); + void LoadDifferences(const CPDF_Dictionary* encoding); void LoadPDFEncoding(bool bEmbedded, bool bTrueType); - CPDF_FontEncoding m_Encoding{PDFFONT_ENCODING_BUILTIN}; - int m_BaseEncoding = PDFFONT_ENCODING_BUILTIN; - bool m_bUseFontWidth; + CPDF_FontEncoding m_Encoding{FontEncoding::kBuiltin}; + FontEncoding m_BaseEncoding = FontEncoding::kBuiltin; + bool m_bUseFontWidth = false; std::vector<ByteString> m_CharNames; - uint16_t m_GlyphIndex[256]; - uint16_t m_CharWidth[256]; - FX_RECT m_CharBBox[256]; + uint16_t m_GlyphIndex[kInternalTableSize]; + uint16_t m_CharWidth[kInternalTableSize]; + FX_RECT m_CharBBox[kInternalTableSize]; }; #endif // CORE_FPDFAPI_FONT_CPDF_SIMPLEFONT_H_
diff --git a/core/fpdfapi/font/cpdf_tounicodemap.cpp b/core/fpdfapi/font/cpdf_tounicodemap.cpp index 1872d5d..3c6e73e 100644 --- a/core/fpdfapi/font/cpdf_tounicodemap.cpp +++ b/core/fpdfapi/font/cpdf_tounicodemap.cpp
@@ -1,4 +1,4 @@ -// Copyright 2017 PDFium Authors. All rights reserved. +// Copyright 2017 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -6,6 +6,7 @@ #include "core/fpdfapi/font/cpdf_tounicodemap.h" +#include <set> #include <utility> #include "core/fpdfapi/font/cpdf_cid2unicodemap.h" @@ -14,6 +15,7 @@ #include "core/fpdfapi/parser/cpdf_stream.h" #include "core/fxcrt/fx_extension.h" #include "core/fxcrt/fx_safe_types.h" +#include "third_party/base/containers/contains.h" #include "third_party/base/numerics/safe_conversions.h" namespace { @@ -37,56 +39,60 @@ } // namespace -CPDF_ToUnicodeMap::CPDF_ToUnicodeMap(const CPDF_Stream* pStream) { - Load(pStream); +CPDF_ToUnicodeMap::CPDF_ToUnicodeMap(RetainPtr<const CPDF_Stream> pStream) { + Load(std::move(pStream)); } CPDF_ToUnicodeMap::~CPDF_ToUnicodeMap() = default; WideString CPDF_ToUnicodeMap::Lookup(uint32_t charcode) const { - auto it = m_Map.find(charcode); - if (it == m_Map.end()) { + auto it = m_Multimap.find(charcode); + if (it == m_Multimap.end()) { if (!m_pBaseMap) return WideString(); - return m_pBaseMap->UnicodeFromCID(static_cast<uint16_t>(charcode)); + return WideString( + m_pBaseMap->UnicodeFromCID(static_cast<uint16_t>(charcode))); } - uint32_t value = it->second; + uint32_t value = *it->second.begin(); wchar_t unicode = static_cast<wchar_t>(value & 0xffff); if (unicode != 0xffff) - return unicode; + return WideString(unicode); - WideStringView buf = m_MultiCharBuf.AsStringView(); size_t index = value >> 16; - if (!buf.IsValidIndex(index)) - return WideString(); - return WideString(buf.Substr(index + 1, buf[index])); + return index < m_MultiCharVec.size() ? m_MultiCharVec[index] : WideString(); } uint32_t CPDF_ToUnicodeMap::ReverseLookup(wchar_t unicode) const { - for (const auto& pair : m_Map) { - if (pair.second == static_cast<uint32_t>(unicode)) + for (const auto& pair : m_Multimap) { + if (pdfium::Contains(pair.second, static_cast<uint32_t>(unicode))) return pair.first; } return 0; } +size_t CPDF_ToUnicodeMap::GetUnicodeCountByCharcodeForTesting( + uint32_t charcode) const { + auto it = m_Multimap.find(charcode); + return it != m_Multimap.end() ? it->second.size() : 0u; +} + // static -pdfium::Optional<uint32_t> CPDF_ToUnicodeMap::StringToCode(ByteStringView str) { +absl::optional<uint32_t> CPDF_ToUnicodeMap::StringToCode(ByteStringView str) { size_t len = str.GetLength(); if (len <= 2 || str[0] != '<' || str[len - 1] != '>') - return pdfium::nullopt; + return absl::nullopt; FX_SAFE_UINT32 code = 0; for (char c : str.Substr(1, len - 2)) { if (!FXSYS_IsHexDigit(c)) - return pdfium::nullopt; + return absl::nullopt; code = code * 16 + FXSYS_HexCharToInt(c); if (!code.IsValid()) - return pdfium::nullopt; + return absl::nullopt; } - return pdfium::Optional<uint32_t>(code.ValueOrDie()); + return absl::optional<uint32_t>(code.ValueOrDie()); } // static @@ -113,12 +119,12 @@ return result; } -void CPDF_ToUnicodeMap::Load(const CPDF_Stream* pStream) { +void CPDF_ToUnicodeMap::Load(RetainPtr<const CPDF_Stream> pStream) { CIDSet cid_set = CIDSET_UNKNOWN; - auto pAcc = pdfium::MakeRetain<CPDF_StreamAcc>(pStream); + auto pAcc = pdfium::MakeRetain<CPDF_StreamAcc>(std::move(pStream)); pAcc->LoadAllDataFiltered(); CPDF_SimpleParser parser(pAcc->GetSpan()); - while (1) { + while (true) { ByteStringView word = parser.GetWord(); if (word.IsEmpty()) break; @@ -136,19 +142,18 @@ else if (word == "/Adobe-GB1-UCS2") cid_set = CIDSET_GB1; } - if (cid_set) { - auto* manager = CPDF_FontGlobals::GetInstance()->GetCMapManager(); - m_pBaseMap = manager->GetCID2UnicodeMap(cid_set); + if (cid_set != CIDSET_UNKNOWN) { + m_pBaseMap = CPDF_FontGlobals::GetInstance()->GetCID2UnicodeMap(cid_set); } } void CPDF_ToUnicodeMap::HandleBeginBFChar(CPDF_SimpleParser* pParser) { - while (1) { + while (true) { ByteStringView word = pParser->GetWord(); if (word.IsEmpty() || word == "endbfchar") return; - pdfium::Optional<uint32_t> code = StringToCode(word); + absl::optional<uint32_t> code = StringToCode(word); if (!code.has_value()) return; @@ -157,17 +162,17 @@ } void CPDF_ToUnicodeMap::HandleBeginBFRange(CPDF_SimpleParser* pParser) { - while (1) { + while (true) { ByteStringView lowcode_str = pParser->GetWord(); if (lowcode_str.IsEmpty() || lowcode_str == "endbfrange") return; - pdfium::Optional<uint32_t> lowcode_opt = StringToCode(lowcode_str); + absl::optional<uint32_t> lowcode_opt = StringToCode(lowcode_str); if (!lowcode_opt.has_value()) return; ByteStringView highcode_str = pParser->GetWord(); - pdfium::Optional<uint32_t> highcode_opt = StringToCode(highcode_str); + absl::optional<uint32_t> highcode_opt = StringToCode(highcode_str); if (!highcode_opt.has_value()) return; @@ -176,36 +181,41 @@ ByteStringView start = pParser->GetWord(); if (start == "[") { - for (uint32_t code = lowcode; code <= highcode; code++) - SetCode(code, StringToWideString(pParser->GetWord())); + for (FX_SAFE_UINT32 code = lowcode; + code.IsValid() && code.ValueOrDie() <= highcode; code++) { + SetCode(code.ValueOrDie(), StringToWideString(pParser->GetWord())); + } pParser->GetWord(); continue; } WideString destcode = StringToWideString(start); if (destcode.GetLength() == 1) { - pdfium::Optional<uint32_t> value_or_error = StringToCode(start); + absl::optional<uint32_t> value_or_error = StringToCode(start); if (!value_or_error.has_value()) return; uint32_t value = value_or_error.value(); - for (uint32_t code = lowcode; code <= highcode; code++) - m_Map[code] = value++; + for (FX_SAFE_UINT32 code = lowcode; + code.IsValid() && code.ValueOrDie() <= highcode; code++) { + InsertIntoMultimap(code.ValueOrDie(), value++); + } } else { - for (uint32_t code = lowcode; code <= highcode; code++) { + for (FX_SAFE_UINT32 code = lowcode; + code.IsValid() && code.ValueOrDie() <= highcode; code++) { + uint32_t code_value = code.ValueOrDie(); WideString retcode = - code == lowcode ? destcode : StringDataAdd(destcode); - m_Map[code] = GetUnicode(); - m_MultiCharBuf.AppendChar(retcode.GetLength()); - m_MultiCharBuf << retcode; + code_value == lowcode ? destcode : StringDataAdd(destcode); + InsertIntoMultimap(code_value, GetMultiCharIndexIndicator()); + m_MultiCharVec.push_back(retcode); destcode = std::move(retcode); } } } } -uint32_t CPDF_ToUnicodeMap::GetUnicode() const { - FX_SAFE_UINT32 uni = m_MultiCharBuf.GetLength(); +uint32_t CPDF_ToUnicodeMap::GetMultiCharIndexIndicator() const { + FX_SAFE_UINT32 uni = m_MultiCharVec.size(); uni = uni * 0x10000 + 0xffff; return uni.ValueOrDefault(0); } @@ -216,10 +226,19 @@ return; if (len == 1) { - m_Map[srccode] = destcode[0]; + InsertIntoMultimap(srccode, destcode[0]); } else { - m_Map[srccode] = GetUnicode(); - m_MultiCharBuf.AppendChar(len); - m_MultiCharBuf << destcode; + InsertIntoMultimap(srccode, GetMultiCharIndexIndicator()); + m_MultiCharVec.push_back(destcode); } } + +void CPDF_ToUnicodeMap::InsertIntoMultimap(uint32_t code, uint32_t destcode) { + auto it = m_Multimap.find(code); + if (it == m_Multimap.end()) { + m_Multimap.emplace(code, std::set<uint32_t>{destcode}); + return; + } + + it->second.emplace(destcode); +}
diff --git a/core/fpdfapi/font/cpdf_tounicodemap.h b/core/fpdfapi/font/cpdf_tounicodemap.h index 9eaf625..a074f45 100644 --- a/core/fpdfapi/font/cpdf_tounicodemap.h +++ b/core/fpdfapi/font/cpdf_tounicodemap.h
@@ -1,4 +1,4 @@ -// Copyright 2017 PDFium Authors. All rights reserved. +// Copyright 2017 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -8,9 +8,13 @@ #define CORE_FPDFAPI_FONT_CPDF_TOUNICODEMAP_H_ #include <map> +#include <set> +#include <vector> -#include "core/fxcrt/cfx_widetextbuf.h" +#include "core/fxcrt/fx_string.h" +#include "core/fxcrt/retain_ptr.h" #include "core/fxcrt/unowned_ptr.h" +#include "third_party/abseil-cpp/absl/types/optional.h" class CPDF_CID2UnicodeMap; class CPDF_SimpleParser; @@ -18,28 +22,34 @@ class CPDF_ToUnicodeMap { public: - explicit CPDF_ToUnicodeMap(const CPDF_Stream* pStream); + explicit CPDF_ToUnicodeMap(RetainPtr<const CPDF_Stream> pStream); ~CPDF_ToUnicodeMap(); WideString Lookup(uint32_t charcode) const; uint32_t ReverseLookup(wchar_t unicode) const; + size_t GetUnicodeCountByCharcodeForTesting(uint32_t charcode) const; + private: friend class cpdf_tounicodemap_StringToCode_Test; friend class cpdf_tounicodemap_StringToWideString_Test; - static pdfium::Optional<uint32_t> StringToCode(ByteStringView str); + static absl::optional<uint32_t> StringToCode(ByteStringView str); static WideString StringToWideString(ByteStringView str); - void Load(const CPDF_Stream* pStream); + void Load(RetainPtr<const CPDF_Stream> pStream); void HandleBeginBFChar(CPDF_SimpleParser* pParser); void HandleBeginBFRange(CPDF_SimpleParser* pParser); - uint32_t GetUnicode() const; + uint32_t GetMultiCharIndexIndicator() const; void SetCode(uint32_t srccode, WideString destcode); - std::map<uint32_t, uint32_t> m_Map; + // Inserts a new entry which hasn't not been inserted into `m_Multimap` + // before. + void InsertIntoMultimap(uint32_t code, uint32_t destcode); + + std::map<uint32_t, std::set<uint32_t>> m_Multimap; UnownedPtr<const CPDF_CID2UnicodeMap> m_pBaseMap; - CFX_WideTextBuf m_MultiCharBuf; + std::vector<WideString> m_MultiCharVec; }; #endif // CORE_FPDFAPI_FONT_CPDF_TOUNICODEMAP_H_
diff --git a/core/fpdfapi/font/cpdf_tounicodemap_unittest.cpp b/core/fpdfapi/font/cpdf_tounicodemap_unittest.cpp index 7dacc5a..86ac2b1 100644 --- a/core/fpdfapi/font/cpdf_tounicodemap_unittest.cpp +++ b/core/fpdfapi/font/cpdf_tounicodemap_unittest.cpp
@@ -1,11 +1,14 @@ -// Copyright 2015 PDFium Authors. All rights reserved. +// Copyright 2015 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "core/fpdfapi/font/cpdf_tounicodemap.h" +#include "core/fpdfapi/parser/cpdf_stream.h" +#include "core/fxcrt/retain_ptr.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" +#include "third_party/base/span.h" TEST(cpdf_tounicodemap, StringToCode) { EXPECT_THAT(CPDF_ToUnicodeMap::StringToCode("<0001>"), testing::Optional(1u)); @@ -47,3 +50,70 @@ EXPECT_EQ(res, CPDF_ToUnicodeMap::StringToWideString("<c2abFaAb>")); EXPECT_EQ(res, CPDF_ToUnicodeMap::StringToWideString("<c2abFaAb12>")); } + +TEST(cpdf_tounicodemap, HandleBeginBFRangeAvoidIntegerOverflow) { + // Make sure there won't be infinite loops due to integer overflows in + // HandleBeginBFRange(). + { + static constexpr uint8_t kInput1[] = + "beginbfrange<FFFFFFFF><FFFFFFFF>[<0041>]endbfrange"; + auto stream = pdfium::MakeRetain<CPDF_Stream>(); + stream->SetData(pdfium::make_span(kInput1)); + CPDF_ToUnicodeMap map(stream); + EXPECT_STREQ(L"A", map.Lookup(0xffffffff).c_str()); + } + { + static constexpr uint8_t kInput2[] = + "beginbfrange<FFFFFFFF><FFFFFFFF><0042>endbfrange"; + auto stream = pdfium::MakeRetain<CPDF_Stream>(); + stream->SetData(pdfium::make_span(kInput2)); + CPDF_ToUnicodeMap map(stream); + EXPECT_STREQ(L"B", map.Lookup(0xffffffff).c_str()); + } + { + static constexpr uint8_t kInput3[] = + "beginbfrange<FFFFFFFF><FFFFFFFF><00410042>endbfrange"; + auto stream = pdfium::MakeRetain<CPDF_Stream>(); + stream->SetData(pdfium::make_span(kInput3)); + CPDF_ToUnicodeMap map(stream); + EXPECT_STREQ(L"AB", map.Lookup(0xffffffff).c_str()); + } +} + +TEST(cpdf_tounicodemap, InsertIntoMultimap) { + { + // Both the CIDs and the unicodes are different. + static constexpr uint8_t kInput1[] = + "beginbfchar<1><0041><2><0042>endbfchar"; + auto stream = pdfium::MakeRetain<CPDF_Stream>(); + stream->SetData(pdfium::make_span(kInput1)); + CPDF_ToUnicodeMap map(stream); + EXPECT_EQ(1u, map.ReverseLookup(0x0041)); + EXPECT_EQ(2u, map.ReverseLookup(0x0042)); + EXPECT_EQ(1u, map.GetUnicodeCountByCharcodeForTesting(1u)); + EXPECT_EQ(1u, map.GetUnicodeCountByCharcodeForTesting(2u)); + } + { + // The same CID with different unicodes. + static constexpr uint8_t kInput2[] = + "beginbfrange<0><0><0041><0><0><0042>endbfrange"; + auto stream = pdfium::MakeRetain<CPDF_Stream>(); + stream->SetData(pdfium::make_span(kInput2)); + CPDF_ToUnicodeMap map(stream); + EXPECT_EQ(0u, map.ReverseLookup(0x0041)); + EXPECT_EQ(0u, map.ReverseLookup(0x0042)); + EXPECT_EQ(2u, map.GetUnicodeCountByCharcodeForTesting(0u)); + } + { + // Duplicate mappings of CID 0 to unicode "A". There should be only 1 entry + // in `m_Multimap`. + static constexpr uint8_t kInput3[] = + "beginbfrange<0><0>[<0041>]endbfrange\n" + "beginbfchar<0><0041>endbfchar"; + auto stream = pdfium::MakeRetain<CPDF_Stream>(); + stream->SetData(pdfium::make_span(kInput3)); + CPDF_ToUnicodeMap map(stream); + EXPECT_EQ(0u, map.ReverseLookup(0x0041)); + EXPECT_EQ(1u, map.GetUnicodeCountByCharcodeForTesting(0u)); + } +}
diff --git a/core/fpdfapi/font/cpdf_truetypefont.cpp b/core/fpdfapi/font/cpdf_truetypefont.cpp index d107ed0..0a59b54 100644 --- a/core/fpdfapi/font/cpdf_truetypefont.cpp +++ b/core/fpdfapi/font/cpdf_truetypefont.cpp
@@ -1,4 +1,4 @@ -// Copyright 2016 PDFium Authors. All rights reserved. +// Copyright 2016 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -6,18 +6,37 @@ #include "core/fpdfapi/font/cpdf_truetypefont.h" +#include <algorithm> +#include <utility> + #include "core/fpdfapi/parser/cpdf_dictionary.h" #include "core/fxge/fx_font.h" +#include "third_party/base/cxx17_backports.h" namespace { -const uint8_t kPrefix[4] = {0x00, 0xf0, 0xf1, 0xf2}; +constexpr uint8_t kPrefix[4] = {0x00, 0xf0, 0xf1, 0xf2}; + +uint16_t GetGlyphIndexForMSSymbol(FXFT_FaceRec* face, uint32_t charcode) { + for (uint8_t c : kPrefix) { + uint16_t unicode = c * 256 + charcode; + uint16_t val = FT_Get_Char_Index(face, unicode); + if (val) + return val; + } + return 0; +} + +bool IsWinAnsiOrMacRomanEncoding(FontEncoding encoding) { + return encoding == FontEncoding::kWinAnsi || + encoding == FontEncoding::kMacRoman; +} } // namespace CPDF_TrueTypeFont::CPDF_TrueTypeFont(CPDF_Document* pDocument, - CPDF_Dictionary* pFontDict) - : CPDF_SimpleFont(pDocument, pFontDict) {} + RetainPtr<CPDF_Dictionary> pFontDict) + : CPDF_SimpleFont(pDocument, std::move(pFontDict)) {} CPDF_TrueTypeFont::~CPDF_TrueTypeFont() = default; @@ -42,86 +61,37 @@ if (!face) return; - int baseEncoding = m_BaseEncoding; - if (m_pFontFile && face->num_charmaps > 0 && - (baseEncoding == PDFFONT_ENCODING_MACROMAN || - baseEncoding == PDFFONT_ENCODING_WINANSI) && - FontStyleIsSymbolic(m_Flags)) { - bool bSupportWin = false; - bool bSupportMac = false; - for (int i = 0; i < FXFT_Get_Face_CharmapCount(face); i++) { - int platform_id = - FXFT_Get_Charmap_PlatformID(FXFT_Get_Face_Charmaps(face)[i]); - if (platform_id == 0 || platform_id == 3) { - bSupportWin = true; - } else if (platform_id == 0 || platform_id == 1) { - bSupportMac = true; - } - } - if (baseEncoding == PDFFONT_ENCODING_WINANSI && !bSupportWin) { - baseEncoding = - bSupportMac ? PDFFONT_ENCODING_MACROMAN : PDFFONT_ENCODING_BUILTIN; - } else if (baseEncoding == PDFFONT_ENCODING_MACROMAN && !bSupportMac) { - baseEncoding = - bSupportWin ? PDFFONT_ENCODING_WINANSI : PDFFONT_ENCODING_BUILTIN; - } - } - if (((baseEncoding == PDFFONT_ENCODING_MACROMAN || - baseEncoding == PDFFONT_ENCODING_WINANSI) && - m_CharNames.empty()) || + const FontEncoding base_encoding = DetermineEncoding(); + if ((IsWinAnsiOrMacRomanEncoding(base_encoding) && m_CharNames.empty()) || FontStyleIsNonSymbolic(m_Flags)) { if (!FXFT_Has_Glyph_Names(face) && (!face->num_charmaps || !face->charmaps)) { - int nStartChar = m_pFontDict->GetIntegerFor("FirstChar"); - if (nStartChar < 0 || nStartChar > 255) - return; - - int charcode = 0; - for (; charcode < nStartChar; charcode++) - m_GlyphIndex[charcode] = 0; - uint16_t nGlyph = charcode - nStartChar + 3; - for (; charcode < 256; charcode++, nGlyph++) - m_GlyphIndex[charcode] = nGlyph; + SetGlyphIndicesFromFirstChar(); return; } - bool bMSUnicode = FT_UseTTCharmap(face, 3, 1); - bool bMacRoman = false; - bool bMSSymbol = false; - if (!bMSUnicode) { - if (FontStyleIsNonSymbolic(m_Flags)) { - bMacRoman = FT_UseTTCharmap(face, 1, 0); - bMSSymbol = !bMacRoman && FT_UseTTCharmap(face, 3, 0); - } else { - bMSSymbol = FT_UseTTCharmap(face, 3, 0); - bMacRoman = !bMSSymbol && FT_UseTTCharmap(face, 1, 0); - } - } + + const CharmapType charmap_type = DetermineCharmapType(); bool bToUnicode = m_pFontDict->KeyExist("ToUnicode"); for (uint32_t charcode = 0; charcode < 256; charcode++) { - const char* name = GetAdobeCharName(baseEncoding, m_CharNames, charcode); + const char* name = GetAdobeCharName(base_encoding, m_CharNames, charcode); if (!name) { m_GlyphIndex[charcode] = m_pFontFile ? FT_Get_Char_Index(face, charcode) : -1; continue; } - m_Encoding.SetUnicode(charcode, PDF_UnicodeFromAdobeName(name)); - if (bMSSymbol) { - for (size_t j = 0; j < FX_ArraySize(kPrefix); j++) { - uint16_t unicode = kPrefix[j] * 256 + charcode; - m_GlyphIndex[charcode] = FT_Get_Char_Index(face, unicode); - if (m_GlyphIndex[charcode]) - break; - } + m_Encoding.SetUnicode(charcode, UnicodeFromAdobeName(name)); + if (charmap_type == CharmapType::kMSSymbol) { + m_GlyphIndex[charcode] = GetGlyphIndexForMSSymbol(face, charcode); } else if (m_Encoding.UnicodeFromCharCode(charcode)) { - if (bMSUnicode) { + if (charmap_type == CharmapType::kMSUnicode) { m_GlyphIndex[charcode] = FT_Get_Char_Index(face, m_Encoding.UnicodeFromCharCode(charcode)); - } else if (bMacRoman) { - uint32_t maccode = - FT_CharCodeFromUnicode(FT_ENCODING_APPLE_ROMAN, - m_Encoding.UnicodeFromCharCode(charcode)); + } else if (charmap_type == CharmapType::kMacRoman) { + uint32_t maccode = CharCodeFromUnicodeForFreetypeEncoding( + FT_ENCODING_APPLE_ROMAN, + m_Encoding.UnicodeFromCharCode(charcode)); if (!maccode) { - m_GlyphIndex[charcode] = FXFT_Get_Name_Index(face, name); + m_GlyphIndex[charcode] = FT_Get_Name_Index(face, name); } else { m_GlyphIndex[charcode] = FT_Get_Char_Index(face, maccode); } @@ -135,7 +105,7 @@ m_GlyphIndex[charcode] = FT_Get_Char_Index(face, 32); continue; } - m_GlyphIndex[charcode] = FXFT_Get_Name_Index(face, name); + m_GlyphIndex[charcode] = FT_Get_Name_Index(face, name); if (m_GlyphIndex[charcode] != 0 || !bToUnicode) continue; @@ -147,70 +117,123 @@ } return; } - if (FT_UseTTCharmap(face, 3, 0)) { - bool bFound = false; - for (int charcode = 0; charcode < 256; charcode++) { - for (size_t j = 0; j < FX_ArraySize(kPrefix); j++) { - uint16_t unicode = kPrefix[j] * 256 + charcode; - m_GlyphIndex[charcode] = FT_Get_Char_Index(face, unicode); - if (m_GlyphIndex[charcode]) { - bFound = true; - break; - } - } - } - if (bFound) { - if (baseEncoding != PDFFONT_ENCODING_BUILTIN) { + if (UseTTCharmapMSSymbol(face)) { + for (uint32_t charcode = 0; charcode < 256; charcode++) + m_GlyphIndex[charcode] = GetGlyphIndexForMSSymbol(face, charcode); + if (HasAnyGlyphIndex()) { + if (base_encoding != FontEncoding::kBuiltin) { for (uint32_t charcode = 0; charcode < 256; charcode++) { const char* name = - GetAdobeCharName(baseEncoding, m_CharNames, charcode); + GetAdobeCharName(base_encoding, m_CharNames, charcode); if (name) - m_Encoding.SetUnicode(charcode, PDF_UnicodeFromAdobeName(name)); + m_Encoding.SetUnicode(charcode, UnicodeFromAdobeName(name)); } - } else if (FT_UseTTCharmap(face, 1, 0)) { - for (int charcode = 0; charcode < 256; charcode++) { - m_Encoding.SetUnicode( - charcode, - FT_UnicodeFromCharCode(FT_ENCODING_APPLE_ROMAN, charcode)); + } else if (UseTTCharmapMacRoman(face)) { + for (uint32_t charcode = 0; charcode < 256; charcode++) { + m_Encoding.SetUnicode(charcode, + UnicodeFromAppleRomanCharCode(charcode)); } } return; } } - if (FT_UseTTCharmap(face, 1, 0)) { - bool bFound = false; - for (int charcode = 0; charcode < 256; charcode++) { + if (UseTTCharmapMacRoman(face)) { + for (uint32_t charcode = 0; charcode < 256; charcode++) { m_GlyphIndex[charcode] = FT_Get_Char_Index(face, charcode); - m_Encoding.SetUnicode( - charcode, FT_UnicodeFromCharCode(FT_ENCODING_APPLE_ROMAN, charcode)); - if (m_GlyphIndex[charcode]) { - bFound = true; - } + m_Encoding.SetUnicode(charcode, UnicodeFromAppleRomanCharCode(charcode)); } - if (m_pFontFile || bFound) + if (m_pFontFile || HasAnyGlyphIndex()) return; } if (FXFT_Select_Charmap(face, FT_ENCODING_UNICODE) == 0) { - bool bFound = false; - const uint16_t* pUnicodes = PDF_UnicodesForPredefinedCharSet(baseEncoding); + const uint16_t* pUnicodes = UnicodesForPredefinedCharSet(base_encoding); for (uint32_t charcode = 0; charcode < 256; charcode++) { if (m_pFontFile) { m_Encoding.SetUnicode(charcode, charcode); } else { - const char* name = GetAdobeCharName(0, m_CharNames, charcode); + const char* name = + GetAdobeCharName(FontEncoding::kBuiltin, m_CharNames, charcode); if (name) - m_Encoding.SetUnicode(charcode, PDF_UnicodeFromAdobeName(name)); + m_Encoding.SetUnicode(charcode, UnicodeFromAdobeName(name)); else if (pUnicodes) m_Encoding.SetUnicode(charcode, pUnicodes[charcode]); } m_GlyphIndex[charcode] = FT_Get_Char_Index(face, m_Encoding.UnicodeFromCharCode(charcode)); - if (m_GlyphIndex[charcode]) - bFound = true; } - if (bFound) + if (HasAnyGlyphIndex()) return; } for (int charcode = 0; charcode < 256; charcode++) m_GlyphIndex[charcode] = charcode; } + +bool CPDF_TrueTypeFont::HasAnyGlyphIndex() const { + for (uint32_t charcode = 0; charcode < kInternalTableSize; charcode++) { + if (m_GlyphIndex[charcode]) + return true; + } + return false; +} + +CPDF_TrueTypeFont::CharmapType CPDF_TrueTypeFont::DetermineCharmapType() const { + if (UseTTCharmapMSUnicode(m_Font.GetFaceRec())) + return CharmapType::kMSUnicode; + + if (FontStyleIsNonSymbolic(m_Flags)) { + if (UseTTCharmapMacRoman(m_Font.GetFaceRec())) + return CharmapType::kMacRoman; + if (UseTTCharmapMSSymbol(m_Font.GetFaceRec())) + return CharmapType::kMSSymbol; + } else { + if (UseTTCharmapMSSymbol(m_Font.GetFaceRec())) + return CharmapType::kMSSymbol; + if (UseTTCharmapMacRoman(m_Font.GetFaceRec())) + return CharmapType::kMacRoman; + } + return CharmapType::kOther; +} + +FontEncoding CPDF_TrueTypeFont::DetermineEncoding() const { + if (!m_pFontFile || !FontStyleIsSymbolic(m_Flags) || + !IsWinAnsiOrMacRomanEncoding(m_BaseEncoding)) { + return m_BaseEncoding; + } + + // Not null - caller checked. + FXFT_FaceRec* face = m_Font.GetFaceRec(); + if (face->num_charmaps <= 0) + return m_BaseEncoding; + + bool support_win = false; + bool support_mac = false; + for (int i = 0; i < face->num_charmaps; i++) { + int platform_id = FXFT_Get_Charmap_PlatformID(face->charmaps[i]); + if (platform_id == kNamePlatformAppleUnicode || + platform_id == kNamePlatformWindows) { + support_win = true; + } else if (platform_id == kNamePlatformMac) { + support_mac = true; + } + if (support_win && support_mac) + break; + } + + if (m_BaseEncoding == FontEncoding::kWinAnsi && !support_win) + return support_mac ? FontEncoding::kMacRoman : FontEncoding::kBuiltin; + if (m_BaseEncoding == FontEncoding::kMacRoman && !support_mac) + return support_win ? FontEncoding::kWinAnsi : FontEncoding::kBuiltin; + return m_BaseEncoding; +} + +void CPDF_TrueTypeFont::SetGlyphIndicesFromFirstChar() { + int start_char = m_pFontDict->GetIntegerFor("FirstChar"); + if (start_char < 0 || start_char > 255) + return; + + auto* it = std::begin(m_GlyphIndex); + std::fill(it, it + start_char, 0); + uint16_t glyph = 3; + for (int charcode = start_char; charcode < 256; charcode++, glyph++) + m_GlyphIndex[charcode] = glyph; +}
diff --git a/core/fpdfapi/font/cpdf_truetypefont.h b/core/fpdfapi/font/cpdf_truetypefont.h index caa1625..cc87073 100644 --- a/core/fpdfapi/font/cpdf_truetypefont.h +++ b/core/fpdfapi/font/cpdf_truetypefont.h
@@ -1,4 +1,4 @@ -// Copyright 2016 PDFium Authors. All rights reserved. +// Copyright 2016 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -8,13 +8,11 @@ #define CORE_FPDFAPI_FONT_CPDF_TRUETYPEFONT_H_ #include "core/fpdfapi/font/cpdf_simplefont.h" -#include "core/fxcrt/fx_system.h" +#include "core/fxcrt/retain_ptr.h" class CPDF_TrueTypeFont final : public CPDF_SimpleFont { public: - template <typename T, typename... Args> - friend RetainPtr<T> pdfium::MakeRetain(Args&&... args); - + CONSTRUCT_VIA_MAKE_RETAIN; ~CPDF_TrueTypeFont() override; // CPDF_Font: @@ -23,13 +21,21 @@ CPDF_TrueTypeFont* AsTrueTypeFont() override; private: - CPDF_TrueTypeFont(CPDF_Document* pDocument, CPDF_Dictionary* pFontDict); + enum class CharmapType { kMSUnicode, kMSSymbol, kMacRoman, kOther }; + + CPDF_TrueTypeFont(CPDF_Document* pDocument, + RetainPtr<CPDF_Dictionary> pFontDict); // CPDF_Font: bool Load() override; // CPDF_SimpleFont: void LoadGlyphMap() override; + + bool HasAnyGlyphIndex() const; + CharmapType DetermineCharmapType() const; + FontEncoding DetermineEncoding() const; + void SetGlyphIndicesFromFirstChar(); }; #endif // CORE_FPDFAPI_FONT_CPDF_TRUETYPEFONT_H_
diff --git a/core/fpdfapi/font/cpdf_type1font.cpp b/core/fpdfapi/font/cpdf_type1font.cpp index 04dd7c2..55510e7 100644 --- a/core/fpdfapi/font/cpdf_type1font.cpp +++ b/core/fpdfapi/font/cpdf_type1font.cpp
@@ -1,4 +1,4 @@ -// Copyright 2016 PDFium Authors. All rights reserved. +// Copyright 2016 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -7,66 +7,67 @@ #include "core/fpdfapi/font/cpdf_type1font.h" #include <algorithm> +#include <iterator> +#include <utility> #include "build/build_config.h" #include "core/fpdfapi/parser/cpdf_dictionary.h" +#include "core/fxcrt/fx_system.h" +#include "core/fxcrt/span_util.h" #include "core/fxge/cfx_fontmapper.h" #include "core/fxge/cfx_gemodule.h" +#include "core/fxge/freetype/fx_freetype.h" #include "core/fxge/fx_font.h" -#include "core/fxge/fx_freetype.h" -#if defined(OS_MACOSX) -#include "core/fxge/apple/apple_int.h" -#endif +#if BUILDFLAG(IS_APPLE) +#include <CoreFoundation/CFString.h> +#include <CoreGraphics/CoreGraphics.h> +#endif // BUILDFLAG(IS_APPLE) namespace { -#if defined(OS_MACOSX) +#if BUILDFLAG(IS_APPLE) struct GlyphNameMap { const char* m_pStrAdobe; // Raw, POD struct. const char* m_pStrUnicode; // Raw, POD struct. }; -const GlyphNameMap g_GlyphNameSubsts[] = {{"ff", "uniFB00"}, - {"ffi", "uniFB03"}, - {"ffl", "uniFB04"}, - {"fi", "uniFB01"}, - {"fl", "uniFB02"}}; +const GlyphNameMap kGlyphNameSubsts[] = {{"ff", "uniFB00"}, + {"ffi", "uniFB03"}, + {"ffl", "uniFB04"}, + {"fi", "uniFB01"}, + {"fl", "uniFB02"}}; const char* GlyphNameRemap(const char* pStrAdobe) { - for (const auto& element : g_GlyphNameSubsts) { + for (const auto& element : kGlyphNameSubsts) { if (!FXSYS_stricmp(element.m_pStrAdobe, pStrAdobe)) return element.m_pStrUnicode; } return nullptr; } -#endif // defined(OS_MACOSX) +#endif // BUILDFLAG(IS_APPLE) bool FT_UseType1Charmap(FXFT_FaceRec* face) { - if (FXFT_Get_Face_CharmapCount(face) == 0) { + if (face->num_charmaps == 0) return false; - } - if (FXFT_Get_Face_CharmapCount(face) == 1 && - FXFT_Get_Charmap_Encoding(FXFT_Get_Face_Charmaps(face)[0]) == - FT_ENCODING_UNICODE) { + + bool is_first_charmap_unicode = + FXFT_Get_Charmap_Encoding(face->charmaps[0]) == FT_ENCODING_UNICODE; + if (face->num_charmaps == 1 && is_first_charmap_unicode) return false; - } - if (FXFT_Get_Charmap_Encoding(FXFT_Get_Face_Charmaps(face)[0]) == - FT_ENCODING_UNICODE) { - FT_Set_Charmap(face, FXFT_Get_Face_Charmaps(face)[1]); - } else { - FT_Set_Charmap(face, FXFT_Get_Face_Charmaps(face)[0]); - } + + int index = is_first_charmap_unicode ? 1 : 0; + FT_Set_Charmap(face, face->charmaps[index]); return true; } } // namespace CPDF_Type1Font::CPDF_Type1Font(CPDF_Document* pDocument, - CPDF_Dictionary* pFontDict) - : CPDF_SimpleFont(pDocument, pFontDict) { -#if defined(OS_MACOSX) + RetainPtr<CPDF_Dictionary> pFontDict) + : CPDF_SimpleFont(pDocument, std::move(pFontDict)) { +#if BUILDFLAG(IS_APPLE) memset(m_ExtGID, 0xff, sizeof(m_ExtGID)); #endif } @@ -90,7 +91,8 @@ if (!IsBase14Font()) return LoadCommon(); - const CPDF_Dictionary* pFontDesc = m_pFontDict->GetDictFor("FontDescriptor"); + RetainPtr<const CPDF_Dictionary> pFontDesc = + m_pFontDict->GetDictFor("FontDescriptor"); if (pFontDesc && pFontDesc->KeyExist("Flags")) { m_Flags = pFontDesc->GetIntegerFor("Flags"); } else if (IsSymbolicFont()) { @@ -99,19 +101,18 @@ m_Flags = FXFONT_NONSYMBOLIC; } if (IsFixedFont()) { - for (int i = 0; i < 256; i++) - m_CharWidth[i] = 600; + std::fill(std::begin(m_CharWidth), std::end(m_CharWidth), 600); } if (m_Base14Font == CFX_FontMapper::kSymbol) - m_BaseEncoding = PDFFONT_ENCODING_ADOBE_SYMBOL; + m_BaseEncoding = FontEncoding::kAdobeSymbol; else if (m_Base14Font == CFX_FontMapper::kDingbats) - m_BaseEncoding = PDFFONT_ENCODING_ZAPFDINGBATS; + m_BaseEncoding = FontEncoding::kZapfDingbats; else if (FontStyleIsNonSymbolic(m_Flags)) - m_BaseEncoding = PDFFONT_ENCODING_STANDARD; + m_BaseEncoding = FontEncoding::kStandard; return LoadCommon(); } -#if defined(OS_MACOSX) +#if BUILDFLAG(IS_APPLE) int CPDF_Type1Font::GlyphFromCharCodeExt(uint32_t charcode) { if (charcode > 0xff) return -1; @@ -125,31 +126,29 @@ if (!m_Font.GetFaceRec()) return; -#if defined(OS_MACOSX) +#if BUILDFLAG(IS_APPLE) bool bCoreText = true; - CQuartz2D& quartz2d = - static_cast<CApplePlatform*>(CFX_GEModule::Get()->GetPlatform()) - ->m_quartz2d; if (!m_Font.GetPlatformFont()) { if (m_Font.GetPsName() == "DFHeiStd-W5") bCoreText = false; + auto* pPlatform = CFX_GEModule::Get()->GetPlatform(); pdfium::span<const uint8_t> span = m_Font.GetFontSpan(); - m_Font.SetPlatformFont(quartz2d.CreateFont(span.data(), span.size())); + m_Font.SetPlatformFont(pPlatform->CreatePlatformFont(span)); if (!m_Font.GetPlatformFont()) bCoreText = false; } #endif if (!IsEmbedded() && !IsSymbolicFont() && m_Font.IsTTFont()) { - if (FT_UseTTCharmap(m_Font.GetFaceRec(), 3, 0)) { + if (UseTTCharmapMSSymbol(m_Font.GetFaceRec())) { bool bGotOne = false; - for (uint32_t charcode = 0; charcode < 256; charcode++) { + for (uint32_t charcode = 0; charcode < kInternalTableSize; charcode++) { const uint8_t prefix[4] = {0x00, 0xf0, 0xf1, 0xf2}; for (int j = 0; j < 4; j++) { uint16_t unicode = prefix[j] * 256 + charcode; m_GlyphIndex[charcode] = FT_Get_Char_Index(m_Font.GetFaceRec(), unicode); -#if defined(OS_MACOSX) +#if BUILDFLAG(IS_APPLE) CalcExtGID(charcode); #endif if (m_GlyphIndex[charcode]) { @@ -159,71 +158,65 @@ } } if (bGotOne) { -#if defined(OS_MACOSX) +#if BUILDFLAG(IS_APPLE) if (!bCoreText) - memcpy(m_ExtGID, m_GlyphIndex, 256); + memcpy(m_ExtGID, m_GlyphIndex, sizeof(m_ExtGID)); #endif return; } } FXFT_Select_Charmap(m_Font.GetFaceRec(), FT_ENCODING_UNICODE); - if (m_BaseEncoding == 0) - m_BaseEncoding = PDFFONT_ENCODING_STANDARD; + if (m_BaseEncoding == FontEncoding::kBuiltin) + m_BaseEncoding = FontEncoding::kStandard; - for (uint32_t charcode = 0; charcode < 256; charcode++) { + for (uint32_t charcode = 0; charcode < kInternalTableSize; charcode++) { const char* name = GetAdobeCharName(m_BaseEncoding, m_CharNames, charcode); if (!name) continue; - m_Encoding.SetUnicode(charcode, PDF_UnicodeFromAdobeName(name)); + m_Encoding.SetUnicode(charcode, UnicodeFromAdobeName(name)); m_GlyphIndex[charcode] = FT_Get_Char_Index( m_Font.GetFaceRec(), m_Encoding.UnicodeFromCharCode(charcode)); -#if defined(OS_MACOSX) +#if BUILDFLAG(IS_APPLE) CalcExtGID(charcode); #endif if (m_GlyphIndex[charcode] == 0 && strcmp(name, ".notdef") == 0) { m_Encoding.SetUnicode(charcode, 0x20); m_GlyphIndex[charcode] = FT_Get_Char_Index(m_Font.GetFaceRec(), 0x20); -#if defined(OS_MACOSX) +#if BUILDFLAG(IS_APPLE) CalcExtGID(charcode); #endif } } -#if defined(OS_MACOSX) - if (!bCoreText) - memcpy(m_ExtGID, m_GlyphIndex, 256); +#if BUILDFLAG(IS_APPLE) + if (!bCoreText) { + fxcrt::spancpy(pdfium::make_span(m_ExtGID), + pdfium::make_span(m_GlyphIndex)); + } #endif return; } FT_UseType1Charmap(m_Font.GetFaceRec()); -#if defined(OS_MACOSX) +#if BUILDFLAG(IS_APPLE) if (bCoreText) { if (FontStyleIsSymbolic(m_Flags)) { - for (uint32_t charcode = 0; charcode < 256; charcode++) { + for (uint32_t charcode = 0; charcode < kInternalTableSize; charcode++) { const char* name = GetAdobeCharName(m_BaseEncoding, m_CharNames, charcode); if (name) { - m_Encoding.SetUnicode(charcode, PDF_UnicodeFromAdobeName(name)); - m_GlyphIndex[charcode] = - FXFT_Get_Name_Index(m_Font.GetFaceRec(), name); + m_Encoding.SetUnicode(charcode, UnicodeFromAdobeName(name)); + m_GlyphIndex[charcode] = FT_Get_Name_Index(m_Font.GetFaceRec(), name); SetExtGID(name, charcode); } else { m_GlyphIndex[charcode] = FT_Get_Char_Index(m_Font.GetFaceRec(), charcode); - wchar_t unicode = 0; - if (m_GlyphIndex[charcode]) { - unicode = - FT_UnicodeFromCharCode(PDFFONT_ENCODING_STANDARD, charcode); - } - char name_glyph[256]; - memset(name_glyph, 0, sizeof(name_glyph)); + char name_glyph[kInternalTableSize] = {}; FT_Get_Glyph_Name(m_Font.GetFaceRec(), m_GlyphIndex[charcode], - name_glyph, 256); - name_glyph[255] = 0; - if (unicode == 0 && name_glyph[0] != 0) - unicode = PDF_UnicodeFromAdobeName(name_glyph); - + name_glyph, sizeof(name_glyph)); + name_glyph[kInternalTableSize - 1] = 0; + const wchar_t unicode = + name_glyph[0] != 0 ? UnicodeFromAdobeName(name_glyph) : 0; m_Encoding.SetUnicode(charcode, unicode); SetExtGID(name_glyph, charcode); } @@ -233,18 +226,18 @@ bool bUnicode = FXFT_Select_Charmap(m_Font.GetFaceRec(), FT_ENCODING_UNICODE) == 0; - for (uint32_t charcode = 0; charcode < 256; charcode++) { + for (uint32_t charcode = 0; charcode < kInternalTableSize; charcode++) { const char* name = GetAdobeCharName(m_BaseEncoding, m_CharNames, charcode); if (!name) continue; - m_Encoding.SetUnicode(charcode, PDF_UnicodeFromAdobeName(name)); + m_Encoding.SetUnicode(charcode, UnicodeFromAdobeName(name)); const char* pStrUnicode = GlyphNameRemap(name); - if (pStrUnicode && FXFT_Get_Name_Index(m_Font.GetFaceRec(), name) == 0) { + if (pStrUnicode && FT_Get_Name_Index(m_Font.GetFaceRec(), name) == 0) { name = pStrUnicode; } - m_GlyphIndex[charcode] = FXFT_Get_Name_Index(m_Font.GetFaceRec(), name); + m_GlyphIndex[charcode] = FT_Get_Name_Index(m_Font.GetFaceRec(), name); SetExtGID(name, charcode); if (m_GlyphIndex[charcode] != 0) continue; @@ -263,65 +256,61 @@ } return; } -#endif // defined(OS_MACOSX) +#endif // BUILDFLAG(IS_APPLE) if (FontStyleIsSymbolic(m_Flags)) { - for (int charcode = 0; charcode < 256; charcode++) { - const char* name = - GetAdobeCharName(m_BaseEncoding, m_CharNames, charcode); + for (size_t charcode = 0; charcode < kInternalTableSize; charcode++) { + const char* name = GetAdobeCharName(m_BaseEncoding, m_CharNames, + static_cast<uint32_t>(charcode)); if (name) { - m_Encoding.SetUnicode(charcode, PDF_UnicodeFromAdobeName(name)); - m_GlyphIndex[charcode] = FXFT_Get_Name_Index(m_Font.GetFaceRec(), name); + m_Encoding.SetUnicode(charcode, UnicodeFromAdobeName(name)); + m_GlyphIndex[charcode] = FT_Get_Name_Index(m_Font.GetFaceRec(), name); } else { - m_GlyphIndex[charcode] = - FT_Get_Char_Index(m_Font.GetFaceRec(), charcode); + m_GlyphIndex[charcode] = FT_Get_Char_Index( + m_Font.GetFaceRec(), static_cast<uint32_t>(charcode)); if (m_GlyphIndex[charcode]) { - wchar_t unicode = - FT_UnicodeFromCharCode(PDFFONT_ENCODING_STANDARD, charcode); - if (unicode == 0) { - char name_glyph[256]; - memset(name_glyph, 0, sizeof(name_glyph)); - FT_Get_Glyph_Name(m_Font.GetFaceRec(), m_GlyphIndex[charcode], - name_glyph, 256); - name_glyph[255] = 0; - if (name_glyph[0] != 0) - unicode = PDF_UnicodeFromAdobeName(name_glyph); - } + char name_glyph[kInternalTableSize] = {}; + FT_Get_Glyph_Name(m_Font.GetFaceRec(), m_GlyphIndex[charcode], + name_glyph, sizeof(name_glyph)); + name_glyph[kInternalTableSize - 1] = 0; + const wchar_t unicode = + name_glyph[0] != 0 ? UnicodeFromAdobeName(name_glyph) : 0; m_Encoding.SetUnicode(charcode, unicode); } } } -#if defined(OS_MACOSX) +#if BUILDFLAG(IS_APPLE) if (!bCoreText) - memcpy(m_ExtGID, m_GlyphIndex, 256); - + memcpy(m_ExtGID, m_GlyphIndex, sizeof(m_ExtGID)); #endif return; } bool bUnicode = FXFT_Select_Charmap(m_Font.GetFaceRec(), FT_ENCODING_UNICODE) == 0; - for (int charcode = 0; charcode < 256; charcode++) { - const char* name = GetAdobeCharName(m_BaseEncoding, m_CharNames, charcode); + for (size_t charcode = 0; charcode < kInternalTableSize; charcode++) { + const char* name = GetAdobeCharName(m_BaseEncoding, m_CharNames, + static_cast<uint32_t>(charcode)); if (!name) continue; - m_Encoding.SetUnicode(charcode, PDF_UnicodeFromAdobeName(name)); - m_GlyphIndex[charcode] = FXFT_Get_Name_Index(m_Font.GetFaceRec(), name); + m_Encoding.SetUnicode(charcode, UnicodeFromAdobeName(name)); + m_GlyphIndex[charcode] = FT_Get_Name_Index(m_Font.GetFaceRec(), name); if (m_GlyphIndex[charcode] != 0) continue; if (strcmp(name, ".notdef") != 0 && strcmp(name, "space") != 0) { - m_GlyphIndex[charcode] = FT_Get_Char_Index( - m_Font.GetFaceRec(), - bUnicode ? m_Encoding.UnicodeFromCharCode(charcode) : charcode); + m_GlyphIndex[charcode] = + FT_Get_Char_Index(m_Font.GetFaceRec(), + bUnicode ? m_Encoding.UnicodeFromCharCode(charcode) + : static_cast<uint32_t>(charcode)); } else { m_Encoding.SetUnicode(charcode, 0x20); m_GlyphIndex[charcode] = 0xffff; } } -#if defined(OS_MACOSX) +#if BUILDFLAG(IS_APPLE) if (!bCoreText) - memcpy(m_ExtGID, m_GlyphIndex, 256); + memcpy(m_ExtGID, m_GlyphIndex, sizeof(m_ExtGID)); #endif } @@ -335,7 +324,7 @@ CFX_FontMapper::IsFixedFont(m_Base14Font.value()); } -#if defined(OS_MACOSX) +#if BUILDFLAG(IS_APPLE) void CPDF_Type1Font::SetExtGID(const char* name, uint32_t charcode) { CFStringRef name_ct = CFStringCreateWithCStringNoCopy( kCFAllocatorDefault, name, kCFStringEncodingASCII, kCFAllocatorNull); @@ -346,10 +335,10 @@ } void CPDF_Type1Font::CalcExtGID(uint32_t charcode) { - char name_glyph[256]; + char name_glyph[kInternalTableSize] = {}; FT_Get_Glyph_Name(m_Font.GetFaceRec(), m_GlyphIndex[charcode], name_glyph, - 256); - name_glyph[255] = 0; + sizeof(name_glyph)); + name_glyph[kInternalTableSize - 1] = 0; SetExtGID(name_glyph, charcode); } -#endif // defined(OS_MACOSX) +#endif // BUILDFLAG(IS_APPLE)
diff --git a/core/fpdfapi/font/cpdf_type1font.h b/core/fpdfapi/font/cpdf_type1font.h index 79dfe31..55f542f 100644 --- a/core/fpdfapi/font/cpdf_type1font.h +++ b/core/fpdfapi/font/cpdf_type1font.h
@@ -1,4 +1,4 @@ -// Copyright 2016 PDFium Authors. All rights reserved. +// Copyright 2016 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -7,30 +7,31 @@ #ifndef CORE_FPDFAPI_FONT_CPDF_TYPE1FONT_H_ #define CORE_FPDFAPI_FONT_CPDF_TYPE1FONT_H_ +#include <stdint.h> + #include "build/build_config.h" #include "core/fpdfapi/font/cpdf_simplefont.h" -#include "core/fxcrt/fx_system.h" +#include "core/fxcrt/retain_ptr.h" #include "core/fxge/cfx_fontmapper.h" class CPDF_Type1Font final : public CPDF_SimpleFont { public: - template <typename T, typename... Args> - friend RetainPtr<T> pdfium::MakeRetain(Args&&... args); - + CONSTRUCT_VIA_MAKE_RETAIN; ~CPDF_Type1Font() override; // CPDF_Font: bool IsType1Font() const override; const CPDF_Type1Font* AsType1Font() const override; CPDF_Type1Font* AsType1Font() override; -#if defined(OS_MACOSX) +#if BUILDFLAG(IS_APPLE) int GlyphFromCharCodeExt(uint32_t charcode) override; #endif bool IsBase14Font() const { return m_Base14Font.has_value(); } private: - CPDF_Type1Font(CPDF_Document* pDocument, CPDF_Dictionary* pFontDict); + CPDF_Type1Font(CPDF_Document* pDocument, + RetainPtr<CPDF_Dictionary> pFontDict); // CPDF_Font: bool Load() override; @@ -41,14 +42,14 @@ bool IsSymbolicFont() const; bool IsFixedFont() const; -#if defined(OS_MACOSX) +#if BUILDFLAG(IS_APPLE) void SetExtGID(const char* name, uint32_t charcode); void CalcExtGID(uint32_t charcode); - uint16_t m_ExtGID[256]; + uint16_t m_ExtGID[kInternalTableSize]; #endif - Optional<CFX_FontMapper::StandardFont> m_Base14Font; + absl::optional<CFX_FontMapper::StandardFont> m_Base14Font; }; #endif // CORE_FPDFAPI_FONT_CPDF_TYPE1FONT_H_
diff --git a/core/fpdfapi/font/cpdf_type3char.cpp b/core/fpdfapi/font/cpdf_type3char.cpp index 3ad9bba..ff9a579 100644 --- a/core/fpdfapi/font/cpdf_type3char.cpp +++ b/core/fpdfapi/font/cpdf_type3char.cpp
@@ -1,4 +1,4 @@ -// Copyright 2016 PDFium Authors. All rights reserved. +// Copyright 2016 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -8,9 +8,9 @@ #include <utility> +#include "core/fxcrt/fx_system.h" #include "core/fxge/dib/cfx_dibitmap.h" -#include "core/fxge/fx_dib.h" -#include "third_party/base/ptr_util.h" +#include "core/fxge/dib/fx_dib.h" namespace { @@ -49,7 +49,7 @@ } void CPDF_Type3Char::InitializeFromStreamData(bool bColored, - const float* pData) { + pdfium::span<const float> pData) { m_bColored = bColored; m_Width = FXSYS_roundf(TextUnitToGlyphUnit(pData[0])); m_BBox.left = FXSYS_roundf(TextUnitToGlyphUnit(pData[2])); @@ -85,7 +85,3 @@ RetainPtr<CFX_DIBitmap> CPDF_Type3Char::GetBitmap() { return m_pBitmap; } - -const RetainPtr<CFX_DIBitmap>& CPDF_Type3Char::GetBitmap() const { - return m_pBitmap; -}
diff --git a/core/fpdfapi/font/cpdf_type3char.h b/core/fpdfapi/font/cpdf_type3char.h index ca83452..afa39ef 100644 --- a/core/fpdfapi/font/cpdf_type3char.h +++ b/core/fpdfapi/font/cpdf_type3char.h
@@ -1,4 +1,4 @@ -// Copyright 2016 PDFium Authors. All rights reserved. +// Copyright 2016 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -12,9 +12,9 @@ #include "core/fpdfapi/font/cpdf_font.h" #include "core/fxcrt/fx_coordinates.h" -#include "core/fxcrt/fx_system.h" #include "core/fxcrt/retain_ptr.h" -#include "third_party/base/optional.h" +#include "third_party/abseil-cpp/absl/types/optional.h" +#include "third_party/base/span.h" class CFX_DIBitmap; @@ -27,15 +27,14 @@ static void TextUnitRectToGlyphUnitRect(CFX_FloatRect* pRect); bool LoadBitmapFromSoleImageOfForm(); - void InitializeFromStreamData(bool bColored, const float* pData); + void InitializeFromStreamData(bool bColored, pdfium::span<const float> pData); void Transform(CPDF_Font::FormIface* pForm, const CFX_Matrix& matrix); void WillBeDestroyed(); RetainPtr<CFX_DIBitmap> GetBitmap(); - const RetainPtr<CFX_DIBitmap>& GetBitmap() const; bool colored() const { return m_bColored; } - uint32_t width() const { return m_Width; } + int width() const { return m_Width; } const CFX_Matrix& matrix() const { return m_ImageMatrix; } const FX_RECT& bbox() const { return m_BBox; } @@ -46,7 +45,7 @@ std::unique_ptr<CPDF_Font::FormIface> m_pForm; RetainPtr<CFX_DIBitmap> m_pBitmap; bool m_bColored = false; - uint32_t m_Width = 0; + int m_Width = 0; CFX_Matrix m_ImageMatrix; FX_RECT m_BBox; };
diff --git a/core/fpdfapi/font/cpdf_type3font.cpp b/core/fpdfapi/font/cpdf_type3font.cpp index eae08ea..866b9e1 100644 --- a/core/fpdfapi/font/cpdf_type3font.cpp +++ b/core/fpdfapi/font/cpdf_type3font.cpp
@@ -1,4 +1,4 @@ -// Copyright 2016 PDFium Authors. All rights reserved. +// Copyright 2016 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -7,6 +7,8 @@ #include "core/fpdfapi/font/cpdf_type3font.h" #include <algorithm> +#include <iterator> +#include <type_traits> #include <utility> #include "core/fpdfapi/font/cpdf_type3char.h" @@ -15,7 +17,7 @@ #include "core/fpdfapi/parser/cpdf_stream.h" #include "core/fxcrt/autorestorer.h" #include "core/fxcrt/fx_system.h" -#include "third_party/base/ptr_util.h" +#include "third_party/base/check.h" namespace { @@ -24,11 +26,11 @@ } // namespace CPDF_Type3Font::CPDF_Type3Font(CPDF_Document* pDocument, - CPDF_Dictionary* pFontDict, + RetainPtr<CPDF_Dictionary> pFontDict, FormFactoryIface* pFormFactory) - : CPDF_SimpleFont(pDocument, pFontDict), m_pFormFactory(pFormFactory) { - ASSERT(GetDocument()); - memset(m_CharWidthL, 0, sizeof(m_CharWidthL)); + : CPDF_SimpleFont(pDocument, std::move(pFontDict)), + m_pFormFactory(pFormFactory) { + DCHECK(GetDocument()); } CPDF_Type3Font::~CPDF_Type3Font() = default; @@ -55,8 +57,8 @@ } bool CPDF_Type3Font::Load() { - m_pFontResources.Reset(m_pFontDict->GetDictFor("Resources")); - const CPDF_Array* pMatrix = m_pFontDict->GetArrayFor("FontMatrix"); + m_pFontResources = m_pFontDict->GetMutableDictFor("Resources"); + RetainPtr<const CPDF_Array> pMatrix = m_pFontDict->GetArrayFor("FontMatrix"); float xscale = 1.0f; float yscale = 1.0f; if (pMatrix) { @@ -65,30 +67,31 @@ yscale = m_FontMatrix.d; } - const CPDF_Array* pBBox = m_pFontDict->GetArrayFor("FontBBox"); + RetainPtr<const CPDF_Array> pBBox = m_pFontDict->GetArrayFor("FontBBox"); if (pBBox) { CFX_FloatRect box( - pBBox->GetNumberAt(0) * xscale, pBBox->GetNumberAt(1) * yscale, - pBBox->GetNumberAt(2) * xscale, pBBox->GetNumberAt(3) * yscale); + pBBox->GetFloatAt(0) * xscale, pBBox->GetFloatAt(1) * yscale, + pBBox->GetFloatAt(2) * xscale, pBBox->GetFloatAt(3) * yscale); CPDF_Type3Char::TextUnitRectToGlyphUnitRect(&box); m_FontBBox = box.ToFxRect(); } - static constexpr size_t kCharLimit = FX_ArraySize(m_CharWidthL); + static constexpr size_t kCharLimit = std::extent<decltype(m_CharWidthL)>(); int StartChar = m_pFontDict->GetIntegerFor("FirstChar"); if (StartChar >= 0 && static_cast<size_t>(StartChar) < kCharLimit) { - const CPDF_Array* pWidthArray = m_pFontDict->GetArrayFor("Widths"); + RetainPtr<const CPDF_Array> pWidthArray = + m_pFontDict->GetArrayFor("Widths"); if (pWidthArray) { size_t count = std::min(pWidthArray->size(), kCharLimit); count = std::min(count, kCharLimit - StartChar); for (size_t i = 0; i < count; i++) { m_CharWidthL[StartChar + i] = FXSYS_roundf(CPDF_Type3Char::TextUnitToGlyphUnit( - pWidthArray->GetNumberAt(i) * xscale)); + pWidthArray->GetFloatAt(i) * xscale)); } } } - m_pCharProcs.Reset(m_pFontDict->GetDictFor("CharProcs")); + m_pCharProcs = m_pFontDict->GetMutableDictFor("CharProcs"); if (m_pFontDict->GetDirectObjectFor("Encoding")) LoadPDFEncoding(false, false); return true; @@ -115,16 +118,16 @@ if (!m_pCharProcs) return nullptr; - CPDF_Stream* pStream = ToStream(m_pCharProcs->GetDirectObjectFor(name)); + RetainPtr<CPDF_Stream> pStream = + ToStream(m_pCharProcs->GetMutableDirectObjectFor(name)); if (!pStream) return nullptr; std::unique_ptr<CPDF_Font::FormIface> pForm = m_pFormFactory->CreateForm( - m_pDocument.Get(), - m_pFontResources ? m_pFontResources.Get() : m_pPageResources.Get(), + m_pDocument, m_pFontResources ? m_pFontResources : m_pPageResources, pStream); - auto pNewChar = pdfium::MakeUnique<CPDF_Type3Char>(); + auto pNewChar = std::make_unique<CPDF_Type3Char>(); // This can trigger recursion into this method. The content of |m_CacheMap| // can change as a result. Thus after it returns, check the cache again for @@ -147,8 +150,8 @@ return pCachedChar; } -uint32_t CPDF_Type3Font::GetCharWidthF(uint32_t charcode) { - if (charcode >= FX_ArraySize(m_CharWidthL)) +int CPDF_Type3Font::GetCharWidthF(uint32_t charcode) { + if (charcode >= std::size(m_CharWidthL)) charcode = 0; if (m_CharWidthL[charcode])
diff --git a/core/fpdfapi/font/cpdf_type3font.h b/core/fpdfapi/font/cpdf_type3font.h index 1ef469b..4f5c650 100644 --- a/core/fpdfapi/font/cpdf_type3font.h +++ b/core/fpdfapi/font/cpdf_type3font.h
@@ -1,4 +1,4 @@ -// Copyright 2016 PDFium Authors. All rights reserved. +// Copyright 2016 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -7,24 +7,23 @@ #ifndef CORE_FPDFAPI_FONT_CPDF_TYPE3FONT_H_ #define CORE_FPDFAPI_FONT_CPDF_TYPE3FONT_H_ +#include <stdint.h> + #include <map> #include <memory> #include "core/fpdfapi/font/cpdf_simplefont.h" #include "core/fxcrt/fx_coordinates.h" -#include "core/fxcrt/fx_system.h" +#include "core/fxcrt/retain_ptr.h" #include "core/fxcrt/unowned_ptr.h" class CPDF_Dictionary; class CPDF_Document; -class CPDF_Stream; class CPDF_Type3Char; class CPDF_Type3Font final : public CPDF_SimpleFont { public: - template <typename T, typename... Args> - friend RetainPtr<T> pdfium::MakeRetain(Args&&... args); - + CONSTRUCT_VIA_MAKE_RETAIN; ~CPDF_Type3Font() override; // CPDF_Font: @@ -32,7 +31,7 @@ const CPDF_Type3Font* AsType3Font() const override; CPDF_Type3Font* AsType3Font() override; void WillBeDestroyed() override; - uint32_t GetCharWidthF(uint32_t charcode) override; + int GetCharWidthF(uint32_t charcode) override; FX_RECT GetCharBBox(uint32_t charcode) override; void SetPageResources(CPDF_Dictionary* pResources) { @@ -45,7 +44,7 @@ private: CPDF_Type3Font(CPDF_Document* pDocument, - CPDF_Dictionary* pFontDict, + RetainPtr<CPDF_Dictionary> pFontDict, FormFactoryIface* pFormFactory); // CPDF_Font: @@ -62,7 +61,7 @@ RetainPtr<CPDF_Dictionary> m_pPageResources; RetainPtr<CPDF_Dictionary> m_pFontResources; std::map<uint32_t, std::unique_ptr<CPDF_Type3Char>> m_CacheMap; - uint32_t m_CharWidthL[256]; + int m_CharWidthL[256] = {}; }; #endif // CORE_FPDFAPI_FONT_CPDF_TYPE3FONT_H_
diff --git a/core/fpdfapi/page/Android.bp b/core/fpdfapi/page/Android.bp index e44cca2..57f3683 100644 --- a/core/fpdfapi/page/Android.bp +++ b/core/fpdfapi/page/Android.bp
@@ -13,11 +13,12 @@ visibility: ["//external/pdfium:__subpackages__"], - header_libs: [ - "libpdfium-constants", + exclude_srcs: [ + "test_with_page_module.cpp", ], static_libs: [ + "libpdfium-constants", "libpdfium-fxcodec", "libpdfium-fxcrt", "libpdfium-fxge",
diff --git a/core/fpdfapi/page/BUILD.gn b/core/fpdfapi/page/BUILD.gn index 2ab0b72..51b4adf 100644 --- a/core/fpdfapi/page/BUILD.gn +++ b/core/fpdfapi/page/BUILD.gn
@@ -1,4 +1,4 @@ -# Copyright 2018 The PDFium Authors. All rights reserved. +# Copyright 2018 The PDFium Authors # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. @@ -11,6 +11,8 @@ "cpdf_allstates.h", "cpdf_annotcontext.cpp", "cpdf_annotcontext.h", + "cpdf_basedcs.cpp", + "cpdf_basedcs.h", "cpdf_clippath.cpp", "cpdf_clippath.h", "cpdf_color.cpp", @@ -47,14 +49,20 @@ "cpdf_iccprofile.h", "cpdf_image.cpp", "cpdf_image.h", + "cpdf_imageloader.cpp", + "cpdf_imageloader.h", "cpdf_imageobject.cpp", "cpdf_imageobject.h", + "cpdf_indexedcs.cpp", + "cpdf_indexedcs.h", "cpdf_meshstream.cpp", "cpdf_meshstream.h", "cpdf_occontext.cpp", "cpdf_occontext.h", "cpdf_page.cpp", "cpdf_page.h", + "cpdf_pageimagecache.cpp", + "cpdf_pageimagecache.h", "cpdf_pagemodule.cpp", "cpdf_pagemodule.h", "cpdf_pageobject.cpp", @@ -99,7 +107,7 @@ "cpdf_transparency.h", "ipdf_page.h", ] - configs += [ "../../../:pdfium_core_config" ] + configs += [ "../../../:pdfium_strict_config" ] deps = [ "../../../constants", "../../fxcodec", @@ -109,20 +117,40 @@ "../parser", ] allow_circular_includes_from = [] - if (pdf_use_skia || pdf_use_skia_paths) { + if (pdf_use_skia) { allow_circular_includes_from += [ "../../fxge" ] } visibility = [ "../../../*" ] } +source_set("unit_test_support") { + testonly = true + sources = [ + "test_with_page_module.cpp", + "test_with_page_module.h", + ] + configs += [ "../../../:pdfium_strict_config" ] + deps = [ + "../page", + "//testing/gtest", + ] +} + pdfium_unittest_source_set("unittests") { sources = [ + "cpdf_colorspace_unittest.cpp", "cpdf_devicecs_unittest.cpp", + "cpdf_function_unittest.cpp", + "cpdf_pageimagecache_unittest.cpp", "cpdf_pageobjectholder_unittest.cpp", "cpdf_psengine_unittest.cpp", "cpdf_streamcontentparser_unittest.cpp", "cpdf_streamparser_unittest.cpp", ] - deps = [ ":page" ] + deps = [ + ":page", + "../parser", + "../render", + ] pdfium_root_dir = "../../../" }
diff --git a/core/fpdfapi/page/cpdf_allstates.cpp b/core/fpdfapi/page/cpdf_allstates.cpp index a12ce33..a4330db 100644 --- a/core/fpdfapi/page/cpdf_allstates.cpp +++ b/core/fpdfapi/page/cpdf_allstates.cpp
@@ -1,4 +1,4 @@ -// Copyright 2016 PDFium Authors. All rights reserved. +// Copyright 2016 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -16,9 +16,9 @@ #include "core/fpdfapi/parser/cpdf_array.h" #include "core/fpdfapi/parser/cpdf_dictionary.h" #include "core/fpdfapi/parser/fpdf_parser_utility.h" +#include "core/fxcrt/bytestring.h" #include "core/fxge/cfx_graphstatedata.h" -#include "third_party/base/compiler_specific.h" -#include "third_party/base/stl_util.h" +#include "third_party/base/cxx17_backports.h" CPDF_AllStates::CPDF_AllStates() = default; @@ -26,6 +26,7 @@ void CPDF_AllStates::Copy(const CPDF_AllStates& src) { CopyStates(src); + m_GraphicsResourceName = src.m_GraphicsResourceName; m_TextMatrix = src.m_TextMatrix; m_ParentMatrix = src.m_ParentMatrix; m_CTM = src.m_CTM; @@ -43,17 +44,15 @@ m_GraphState.SetLineDash(std::move(dashes), phase, scale); } -void CPDF_AllStates::ProcessExtGS(CPDF_Dictionary* pGS, +void CPDF_AllStates::ProcessExtGS(const CPDF_Dictionary* pGS, CPDF_StreamContentParser* pParser) { CPDF_DictionaryLocker locker(pGS); for (const auto& it : locker) { - const ByteString& key_str = it.first; - CPDF_Object* pElement = it.second.Get(); - CPDF_Object* pObject = pElement ? pElement->GetDirect() : nullptr; + RetainPtr<CPDF_Object> pObject = it.second->GetMutableDirect(); if (!pObject) continue; - uint32_t key = key_str.GetID(); + uint32_t key = it.first.GetID(); switch (key) { case FXBSTR_ID('L', 'W', 0, 0): m_GraphState.SetLineWidth(pObject->GetNumber()); @@ -70,53 +69,52 @@ m_GraphState.SetMiterLimit(pObject->GetNumber()); break; case FXBSTR_ID('D', 0, 0, 0): { - CPDF_Array* pDash = pObject->AsArray(); + const CPDF_Array* pDash = pObject->AsArray(); if (!pDash) break; - CPDF_Array* pArray = pDash->GetArrayAt(0); + RetainPtr<const CPDF_Array> pArray = pDash->GetArrayAt(0); if (!pArray) break; - SetLineDash(pArray, pDash->GetNumberAt(1), 1.0f); + SetLineDash(pArray.Get(), pDash->GetFloatAt(1), 1.0f); break; } case FXBSTR_ID('R', 'I', 0, 0): m_GeneralState.SetRenderIntent(pObject->GetString()); break; case FXBSTR_ID('F', 'o', 'n', 't'): { - CPDF_Array* pFont = pObject->AsArray(); + const CPDF_Array* pFont = pObject->AsArray(); if (!pFont) break; - m_TextState.SetFontSize(pFont->GetNumberAt(1)); - m_TextState.SetFont(pParser->FindFont(pFont->GetStringAt(0))); + m_TextState.SetFontSize(pFont->GetFloatAt(1)); + m_TextState.SetFont(pParser->FindFont(pFont->GetByteStringAt(0))); break; } case FXBSTR_ID('T', 'R', 0, 0): if (pGS->KeyExist("TR2")) { continue; } - FALLTHROUGH; + [[fallthrough]]; case FXBSTR_ID('T', 'R', '2', 0): - m_GeneralState.SetTR(pObject && !pObject->IsName() ? pObject : nullptr); + m_GeneralState.SetTR(!pObject->IsName() ? std::move(pObject) : nullptr); break; case FXBSTR_ID('B', 'M', 0, 0): { - CPDF_Array* pArray = pObject->AsArray(); - m_GeneralState.SetBlendMode(pArray ? pArray->GetStringAt(0) + const CPDF_Array* pArray = pObject->AsArray(); + m_GeneralState.SetBlendMode(pArray ? pArray->GetByteStringAt(0) : pObject->GetString()); if (m_GeneralState.GetBlendType() > BlendMode::kMultiply) pParser->GetPageObjectHolder()->SetBackgroundAlphaNeeded(true); break; } - case FXBSTR_ID('S', 'M', 'a', 's'): - if (ToDictionary(pObject)) { - m_GeneralState.SetSoftMask(pObject); + case FXBSTR_ID('S', 'M', 'a', 's'): { + RetainPtr<CPDF_Dictionary> pMaskDict = ToDictionary(pObject); + m_GeneralState.SetSoftMask(pMaskDict); + if (pMaskDict) m_GeneralState.SetSMaskMatrix(pParser->GetCurStates()->m_CTM); - } else { - m_GeneralState.SetSoftMask(nullptr); - } break; + } case FXBSTR_ID('C', 'A', 0, 0): m_GeneralState.SetStrokeAlpha( pdfium::clamp(pObject->GetNumber(), 0.0f, 1.0f)); @@ -140,20 +138,20 @@ if (pGS->KeyExist("BG2")) { continue; } - FALLTHROUGH; + [[fallthrough]]; case FXBSTR_ID('B', 'G', '2', 0): - m_GeneralState.SetBG(pObject); + m_GeneralState.SetBG(std::move(pObject)); break; case FXBSTR_ID('U', 'C', 'R', 0): if (pGS->KeyExist("UCR2")) { continue; } - FALLTHROUGH; + [[fallthrough]]; case FXBSTR_ID('U', 'C', 'R', '2'): - m_GeneralState.SetUCR(pObject); + m_GeneralState.SetUCR(std::move(pObject)); break; case FXBSTR_ID('H', 'T', 0, 0): - m_GeneralState.SetHT(pObject); + m_GeneralState.SetHT(std::move(pObject)); break; case FXBSTR_ID('F', 'L', 0, 0): m_GeneralState.SetFlatness(pObject->GetNumber());
diff --git a/core/fpdfapi/page/cpdf_allstates.h b/core/fpdfapi/page/cpdf_allstates.h index dc6f17f..63eb527 100644 --- a/core/fpdfapi/page/cpdf_allstates.h +++ b/core/fpdfapi/page/cpdf_allstates.h
@@ -1,4 +1,4 @@ -// Copyright 2016 PDFium Authors. All rights reserved. +// Copyright 2016 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -8,8 +8,8 @@ #define CORE_FPDFAPI_PAGE_CPDF_ALLSTATES_H_ #include "core/fpdfapi/page/cpdf_graphicstates.h" +#include "core/fxcrt/bytestring.h" #include "core/fxcrt/fx_coordinates.h" -#include "core/fxcrt/fx_system.h" class CPDF_Array; class CPDF_Dictionary; @@ -21,9 +21,11 @@ ~CPDF_AllStates() override; void Copy(const CPDF_AllStates& src); - void ProcessExtGS(CPDF_Dictionary* pGS, CPDF_StreamContentParser* pParser); + void ProcessExtGS(const CPDF_Dictionary* pGS, + CPDF_StreamContentParser* pParser); void SetLineDash(const CPDF_Array* pArray, float phase, float scale); + ByteString m_GraphicsResourceName; CFX_Matrix m_TextMatrix; CFX_Matrix m_CTM; CFX_Matrix m_ParentMatrix;
diff --git a/core/fpdfapi/page/cpdf_annotcontext.cpp b/core/fpdfapi/page/cpdf_annotcontext.cpp index 1078e46..7148a09 100644 --- a/core/fpdfapi/page/cpdf_annotcontext.cpp +++ b/core/fpdfapi/page/cpdf_annotcontext.cpp
@@ -1,4 +1,4 @@ -// Copyright 2018 PDFium Authors. All rights reserved. +// Copyright 2018 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -6,30 +6,34 @@ #include "core/fpdfapi/page/cpdf_annotcontext.h" +#include <utility> + #include "core/fpdfapi/page/cpdf_form.h" #include "core/fpdfapi/page/cpdf_page.h" #include "core/fpdfapi/parser/cpdf_dictionary.h" #include "core/fpdfapi/parser/cpdf_stream.h" -#include "third_party/base/ptr_util.h" +#include "third_party/base/check.h" -CPDF_AnnotContext::CPDF_AnnotContext(CPDF_Dictionary* pAnnotDict, - CPDF_Page* pPage) - : m_pAnnotDict(pAnnotDict), m_pPage(pPage) { - ASSERT(m_pAnnotDict); - ASSERT(m_pPage); +CPDF_AnnotContext::CPDF_AnnotContext(RetainPtr<CPDF_Dictionary> pAnnotDict, + IPDF_Page* pPage) + : m_pAnnotDict(std::move(pAnnotDict)), m_pPage(pPage) { + DCHECK(m_pAnnotDict); + DCHECK(m_pPage); + DCHECK(m_pPage->AsPDFPage()); } CPDF_AnnotContext::~CPDF_AnnotContext() = default; -void CPDF_AnnotContext::SetForm(CPDF_Stream* pStream) { +void CPDF_AnnotContext::SetForm(RetainPtr<CPDF_Stream> pStream) { if (!pStream) return; // Reset the annotation matrix to be the identity matrix, since the // appearance stream already takes matrix into account. - pStream->GetDict()->SetMatrixFor("Matrix", CFX_Matrix()); + pStream->GetMutableDict()->SetMatrixFor("Matrix", CFX_Matrix()); - m_pAnnotForm = pdfium::MakeUnique<CPDF_Form>( - m_pPage->GetDocument(), m_pPage->m_pResources.Get(), pStream); + m_pAnnotForm = std::make_unique<CPDF_Form>( + m_pPage->GetDocument(), m_pPage->AsPDFPage()->GetMutableResources(), + pStream); m_pAnnotForm->ParseContent(); }
diff --git a/core/fpdfapi/page/cpdf_annotcontext.h b/core/fpdfapi/page/cpdf_annotcontext.h index ee9f3fc..dee2ad3 100644 --- a/core/fpdfapi/page/cpdf_annotcontext.h +++ b/core/fpdfapi/page/cpdf_annotcontext.h
@@ -1,4 +1,4 @@ -// Copyright 2018 PDFium Authors. All rights reserved. +// Copyright 2018 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -14,28 +14,29 @@ class CPDF_Dictionary; class CPDF_Form; -class CPDF_Page; class CPDF_Stream; +class IPDF_Page; class CPDF_AnnotContext { public: - CPDF_AnnotContext(CPDF_Dictionary* pAnnotDict, CPDF_Page* pPage); + CPDF_AnnotContext(RetainPtr<CPDF_Dictionary> pAnnotDict, IPDF_Page* pPage); ~CPDF_AnnotContext(); - void SetForm(CPDF_Stream* pStream); + void SetForm(RetainPtr<CPDF_Stream> pStream); bool HasForm() const { return !!m_pAnnotForm; } CPDF_Form* GetForm() const { return m_pAnnotForm.get(); } // Never nullptr. - CPDF_Dictionary* GetAnnotDict() const { return m_pAnnotDict.Get(); } + RetainPtr<CPDF_Dictionary> GetMutableAnnotDict() { return m_pAnnotDict; } + const CPDF_Dictionary* GetAnnotDict() const { return m_pAnnotDict.Get(); } // Never nullptr. - CPDF_Page* GetPage() const { return m_pPage.Get(); } + IPDF_Page* GetPage() const { return m_pPage; } private: std::unique_ptr<CPDF_Form> m_pAnnotForm; RetainPtr<CPDF_Dictionary> const m_pAnnotDict; - UnownedPtr<CPDF_Page> const m_pPage; + UnownedPtr<IPDF_Page> const m_pPage; }; #endif // CORE_FPDFAPI_PAGE_CPDF_ANNOTCONTEXT_H_
diff --git a/core/fpdfapi/page/cpdf_basedcs.cpp b/core/fpdfapi/page/cpdf_basedcs.cpp new file mode 100644 index 0000000..c8988bb --- /dev/null +++ b/core/fpdfapi/page/cpdf_basedcs.cpp
@@ -0,0 +1,17 @@ +// Copyright 2021 The PDFium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com + +#include "core/fpdfapi/page/cpdf_basedcs.h" + +CPDF_BasedCS::CPDF_BasedCS(Family family) : CPDF_ColorSpace(family) {} + +CPDF_BasedCS::~CPDF_BasedCS() = default; + +void CPDF_BasedCS::EnableStdConversion(bool bEnabled) { + CPDF_ColorSpace::EnableStdConversion(bEnabled); + if (m_pBaseCS) + m_pBaseCS->EnableStdConversion(bEnabled); +}
diff --git a/core/fpdfapi/page/cpdf_basedcs.h b/core/fpdfapi/page/cpdf_basedcs.h new file mode 100644 index 0000000..7c72f1e --- /dev/null +++ b/core/fpdfapi/page/cpdf_basedcs.h
@@ -0,0 +1,29 @@ +// Copyright 2021 The PDFium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com + +#ifndef CORE_FPDFAPI_PAGE_CPDF_BASEDCS_H_ +#define CORE_FPDFAPI_PAGE_CPDF_BASEDCS_H_ + +#include "core/fpdfapi/page/cpdf_colorspace.h" +#include "core/fxcrt/retain_ptr.h" + +// Represents a color space that is based on another color space. This includes +// all the special color spaces in ISO 32000-1:2008, table 62, as well as the +// ICCBased color space. +class CPDF_BasedCS : public CPDF_ColorSpace { + public: + CONSTRUCT_VIA_MAKE_RETAIN; + ~CPDF_BasedCS() override; + + void EnableStdConversion(bool bEnabled) final; + + protected: + explicit CPDF_BasedCS(Family family); + + RetainPtr<CPDF_ColorSpace> m_pBaseCS; // May be fallback CS in some cases. +}; + +#endif // CORE_FPDFAPI_PAGE_CPDF_BASEDCS_H_
diff --git a/core/fpdfapi/page/cpdf_clippath.cpp b/core/fpdfapi/page/cpdf_clippath.cpp index 53b602d..032aff6 100644 --- a/core/fpdfapi/page/cpdf_clippath.cpp +++ b/core/fpdfapi/page/cpdf_clippath.cpp
@@ -1,4 +1,4 @@ -// Copyright 2016 PDFium Authors. All rights reserved. +// Copyright 2016 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -26,7 +26,7 @@ return m_Ref.GetObject()->m_PathAndTypeList[i].first; } -uint8_t CPDF_ClipPath::GetClipType(size_t i) const { +CFX_FillRenderOptions::FillType CPDF_ClipPath::GetClipType(size_t i) const { return m_Ref.GetObject()->m_PathAndTypeList[i].second; } @@ -74,9 +74,17 @@ return rect; } -void CPDF_ClipPath::AppendPath(CPDF_Path path, uint8_t type, bool bAutoMerge) { +void CPDF_ClipPath::AppendPath(CPDF_Path path, + CFX_FillRenderOptions::FillType type) { PathData* pData = m_Ref.GetPrivateCopy(); - if (!pData->m_PathAndTypeList.empty() && bAutoMerge) { + pData->m_PathAndTypeList.emplace_back(path, type); +} + +void CPDF_ClipPath::AppendPathWithAutoMerge( + CPDF_Path path, + CFX_FillRenderOptions::FillType type) { + PathData* pData = m_Ref.GetPrivateCopy(); + if (!pData->m_PathAndTypeList.empty()) { const CPDF_Path& old_path = pData->m_PathAndTypeList.back().first; if (old_path.IsRect()) { CFX_PointF point0 = old_path.GetPoint(0); @@ -87,7 +95,7 @@ pData->m_PathAndTypeList.pop_back(); } } - pData->m_PathAndTypeList.push_back(std::make_pair(path, type)); + AppendPath(path, type); } void CPDF_ClipPath::AppendTexts( @@ -107,7 +115,7 @@ return; for (size_t i = 0; i < that.GetPathCount(); ++i) - AppendPath(that.GetPath(i), that.GetClipType(i), /*bAutoMerge=*/false); + AppendPath(that.GetPath(i), that.GetClipType(i)); } void CPDF_ClipPath::Transform(const CFX_Matrix& matrix) { @@ -123,10 +131,9 @@ CPDF_ClipPath::PathData::PathData() = default; -CPDF_ClipPath::PathData::PathData(const PathData& that) { - m_PathAndTypeList = that.m_PathAndTypeList; - - m_TextList.resize(that.m_TextList.size()); +CPDF_ClipPath::PathData::PathData(const PathData& that) + : m_PathAndTypeList(that.m_PathAndTypeList), + m_TextList(that.m_TextList.size()) { for (size_t i = 0; i < that.m_TextList.size(); ++i) { if (that.m_TextList[i]) m_TextList[i] = that.m_TextList[i]->Clone();
diff --git a/core/fpdfapi/page/cpdf_clippath.h b/core/fpdfapi/page/cpdf_clippath.h index aff2839..e93f9a8 100644 --- a/core/fpdfapi/page/cpdf_clippath.h +++ b/core/fpdfapi/page/cpdf_clippath.h
@@ -1,4 +1,4 @@ -// Copyright 2016 PDFium Authors. All rights reserved. +// Copyright 2016 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -13,7 +13,9 @@ #include "core/fpdfapi/page/cpdf_path.h" #include "core/fxcrt/fx_coordinates.h" +#include "core/fxcrt/retain_ptr.h" #include "core/fxcrt/shared_copy_on_write.h" +#include "core/fxge/cfx_fillrenderoptions.h" class CPDF_TextObject; @@ -35,11 +37,13 @@ size_t GetPathCount() const; CPDF_Path GetPath(size_t i) const; - uint8_t GetClipType(size_t i) const; + CFX_FillRenderOptions::FillType GetClipType(size_t i) const; size_t GetTextCount() const; CPDF_TextObject* GetText(size_t i) const; CFX_FloatRect GetClipBox() const; - void AppendPath(CPDF_Path path, uint8_t type, bool bAutoMerge); + void AppendPath(CPDF_Path path, CFX_FillRenderOptions::FillType type); + void AppendPathWithAutoMerge(CPDF_Path path, + CFX_FillRenderOptions::FillType type); void AppendTexts(std::vector<std::unique_ptr<CPDF_TextObject>>* pTexts); void CopyClipPath(const CPDF_ClipPath& that); void Transform(const CFX_Matrix& matrix); @@ -47,12 +51,12 @@ private: class PathData final : public Retainable { public: - template <typename T, typename... Args> - friend RetainPtr<T> pdfium::MakeRetain(Args&&... args); + CONSTRUCT_VIA_MAKE_RETAIN; RetainPtr<PathData> Clone() const; - using PathAndTypeData = std::pair<CPDF_Path, uint8_t>; + using PathAndTypeData = + std::pair<CPDF_Path, CFX_FillRenderOptions::FillType>; std::vector<PathAndTypeData> m_PathAndTypeList; std::vector<std::unique_ptr<CPDF_TextObject>> m_TextList;
diff --git a/core/fpdfapi/page/cpdf_color.cpp b/core/fpdfapi/page/cpdf_color.cpp index cfa6422..57e483c 100644 --- a/core/fpdfapi/page/cpdf_color.cpp +++ b/core/fpdfapi/page/cpdf_color.cpp
@@ -1,4 +1,4 @@ -// Copyright 2016 PDFium Authors. All rights reserved. +// Copyright 2016 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -6,11 +6,10 @@ #include "core/fpdfapi/page/cpdf_color.h" -#include "core/fpdfapi/page/cpdf_docpagedata.h" +#include <utility> + #include "core/fpdfapi/page/cpdf_patterncs.h" -#include "core/fpdfapi/parser/cpdf_array.h" -#include "core/fpdfapi/parser/cpdf_document.h" -#include "core/fxcrt/fx_system.h" +#include "third_party/base/check.h" CPDF_Color::CPDF_Color() = default; @@ -25,35 +24,36 @@ } bool CPDF_Color::IsPatternInternal() const { - return m_pCS->GetFamily() == PDFCS_PATTERN; + return m_pCS->GetFamily() == CPDF_ColorSpace::Family::kPattern; } -void CPDF_Color::SetColorSpace(const RetainPtr<CPDF_ColorSpace>& pCS) { - m_pCS = pCS; +void CPDF_Color::SetColorSpace(RetainPtr<CPDF_ColorSpace> colorspace) { + m_pCS = std::move(colorspace); if (IsPatternInternal()) { m_Buffer.clear(); - m_pValue = pdfium::MakeUnique<PatternValue>(); + m_pValue = std::make_unique<PatternValue>(); } else { - m_Buffer = pCS->CreateBufAndSetDefaultColor(); + m_Buffer = m_pCS->CreateBufAndSetDefaultColor(); m_pValue.reset(); } } -void CPDF_Color::SetValueForNonPattern(const std::vector<float>& values) { - ASSERT(!IsPatternInternal()); - ASSERT(m_pCS->CountComponents() <= values.size()); - m_Buffer = values; +void CPDF_Color::SetValueForNonPattern(std::vector<float> values) { + DCHECK(!IsPatternInternal()); + DCHECK(m_pCS->CountComponents() <= values.size()); + m_Buffer = std::move(values); } -void CPDF_Color::SetValueForPattern(const RetainPtr<CPDF_Pattern>& pPattern, - const std::vector<float>& values) { +void CPDF_Color::SetValueForPattern(RetainPtr<CPDF_Pattern> pattern, + pdfium::span<float> values) { if (values.size() > kMaxPatternColorComps) return; - if (!IsPattern()) - SetColorSpace(CPDF_ColorSpace::GetStockCS(PDFCS_PATTERN)); - - m_pValue->SetPattern(pPattern); + if (!IsPattern()) { + SetColorSpace( + CPDF_ColorSpace::GetStockCS(CPDF_ColorSpace::Family::kPattern)); + } + m_pValue->SetPattern(std::move(pattern)); m_pValue->SetComps(values); } @@ -62,8 +62,8 @@ return *this; m_Buffer = that.m_Buffer; - m_pValue = that.m_pValue ? pdfium::MakeUnique<PatternValue>(*that.m_pValue) - : nullptr; + m_pValue = + that.m_pValue ? std::make_unique<PatternValue>(*that.m_pValue) : nullptr; m_pCS = that.m_pCS; return *this; } @@ -73,7 +73,8 @@ } bool CPDF_Color::IsColorSpaceRGB() const { - return m_pCS == CPDF_ColorSpace::GetStockCS(PDFCS_DEVICERGB); + return m_pCS == + CPDF_ColorSpace::GetStockCS(CPDF_ColorSpace::Family::kDeviceRGB); } bool CPDF_Color::GetRGB(int* R, int* G, int* B) const { @@ -88,7 +89,7 @@ } } else { if (!m_Buffer.empty()) - result = m_pCS->GetRGB(m_Buffer.data(), &r, &g, &b); + result = m_pCS->GetRGB(m_Buffer, &r, &g, &b); } if (!result) return false; @@ -99,7 +100,7 @@ return true; } -CPDF_Pattern* CPDF_Color::GetPattern() const { - ASSERT(IsPattern()); +RetainPtr<CPDF_Pattern> CPDF_Color::GetPattern() const { + DCHECK(IsPattern()); return m_pValue ? m_pValue->GetPattern() : nullptr; }
diff --git a/core/fpdfapi/page/cpdf_color.h b/core/fpdfapi/page/cpdf_color.h index b533d08..d3e605b 100644 --- a/core/fpdfapi/page/cpdf_color.h +++ b/core/fpdfapi/page/cpdf_color.h
@@ -1,4 +1,4 @@ -// Copyright 2016 PDFium Authors. All rights reserved. +// Copyright 2016 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -7,11 +7,13 @@ #ifndef CORE_FPDFAPI_PAGE_CPDF_COLOR_H_ #define CORE_FPDFAPI_PAGE_CPDF_COLOR_H_ +#include <stdint.h> + #include <memory> #include <vector> -#include "core/fxcrt/fx_system.h" #include "core/fxcrt/retain_ptr.h" +#include "third_party/base/span.h" class CPDF_ColorSpace; class CPDF_Pattern; @@ -28,16 +30,17 @@ bool IsNull() const { return m_Buffer.empty() && !m_pValue; } bool IsPattern() const; - void SetColorSpace(const RetainPtr<CPDF_ColorSpace>& pCS); - void SetValueForNonPattern(const std::vector<float>& values); - void SetValueForPattern(const RetainPtr<CPDF_Pattern>& pPattern, - const std::vector<float>& values); + void SetColorSpace(RetainPtr<CPDF_ColorSpace> colorspace); + void SetValueForNonPattern(std::vector<float> values); + void SetValueForPattern(RetainPtr<CPDF_Pattern> pattern, + pdfium::span<float> values); + uint32_t CountComponents() const; bool IsColorSpaceRGB() const; bool GetRGB(int* R, int* G, int* B) const; // Should only be called if IsPattern() returns true. - CPDF_Pattern* GetPattern() const; + RetainPtr<CPDF_Pattern> GetPattern() const; protected: bool IsPatternInternal() const;
diff --git a/core/fpdfapi/page/cpdf_colorspace.cpp b/core/fpdfapi/page/cpdf_colorspace.cpp index fd4a2ad..9d94acd 100644 --- a/core/fpdfapi/page/cpdf_colorspace.cpp +++ b/core/fpdfapi/page/cpdf_colorspace.cpp
@@ -1,4 +1,4 @@ -// Copyright 2016 PDFium Authors. All rights reserved. +// Copyright 2016 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -6,9 +6,13 @@ #include "core/fpdfapi/page/cpdf_colorspace.h" +#include <math.h> +#include <stdint.h> + #include <algorithm> #include <limits> #include <memory> +#include <type_traits> #include <utility> #include <vector> @@ -16,6 +20,7 @@ #include "core/fpdfapi/page/cpdf_docpagedata.h" #include "core/fpdfapi/page/cpdf_function.h" #include "core/fpdfapi/page/cpdf_iccprofile.h" +#include "core/fpdfapi/page/cpdf_indexedcs.h" #include "core/fpdfapi/page/cpdf_pagemodule.h" #include "core/fpdfapi/page/cpdf_pattern.h" #include "core/fpdfapi/page/cpdf_patterncs.h" @@ -25,19 +30,25 @@ #include "core/fpdfapi/parser/cpdf_name.h" #include "core/fpdfapi/parser/cpdf_object.h" #include "core/fpdfapi/parser/cpdf_stream.h" -#include "core/fpdfapi/parser/cpdf_stream_acc.h" -#include "core/fpdfapi/parser/cpdf_string.h" #include "core/fpdfapi/parser/fpdf_parser_utility.h" #include "core/fxcodec/fx_codec.h" -#include "core/fxcodec/icc/iccmodule.h" -#include "core/fxcrt/fx_memory.h" +#include "core/fxcrt/data_vector.h" +#include "core/fxcrt/fx_2d_size.h" +#include "core/fxcrt/fx_memory_wrappers.h" #include "core/fxcrt/fx_safe_types.h" #include "core/fxcrt/maybe_owned.h" -#include "third_party/base/stl_util.h" +#include "core/fxcrt/scoped_set_insertion.h" +#include "core/fxcrt/span_util.h" +#include "core/fxcrt/stl_util.h" +#include "third_party/base/check.h" +#include "third_party/base/check_op.h" +#include "third_party/base/containers/contains.h" +#include "third_party/base/cxx17_backports.h" +#include "third_party/base/notreached.h" namespace { -const uint8_t g_sRGBSamples1[] = { +constexpr uint8_t kSRGBSamples1[] = { 0, 3, 6, 10, 13, 15, 18, 20, 22, 23, 25, 27, 28, 30, 31, 32, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 49, 50, 51, 52, 53, 53, 54, 55, 56, 56, 57, 58, 58, @@ -53,7 +64,7 @@ 116, 117, 117, 117, 118, 118, 118, 118, 119, 119, 119, 120, }; -const uint8_t g_sRGBSamples2[] = { +constexpr uint8_t kSRGBSamples2[] = { 120, 121, 122, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 148, 149, 150, 151, 152, 153, 154, 155, 155, 156, 157, 158, 159, 159, 160, 161, 162, @@ -79,7 +90,7 @@ } void GetBlackPoint(const CPDF_Dictionary* pDict, float* pPoints) { - const CPDF_Array* pParam = pDict->GetArrayFor("BlackPoint"); + RetainPtr<const CPDF_Array> pParam = pDict->GetArrayFor("BlackPoint"); if (!pParam || pParam->size() != kBlackWhitePointCount) { GetDefaultBlackPoint(pPoints); return; @@ -87,7 +98,7 @@ // Check to make sure all values are non-negative. for (size_t i = 0; i < kBlackWhitePointCount; ++i) { - pPoints[i] = pParam->GetNumberAt(i); + pPoints[i] = pParam->GetFloatAt(i); if (pPoints[i] < 0) { GetDefaultBlackPoint(pPoints); return; @@ -96,29 +107,30 @@ } bool GetWhitePoint(const CPDF_Dictionary* pDict, float* pPoints) { - const CPDF_Array* pParam = pDict->GetArrayFor("WhitePoint"); + RetainPtr<const CPDF_Array> pParam = pDict->GetArrayFor("WhitePoint"); if (!pParam || pParam->size() != kBlackWhitePointCount) return false; for (size_t i = 0; i < kBlackWhitePointCount; ++i) - pPoints[i] = pParam->GetNumberAt(i); + pPoints[i] = pParam->GetFloatAt(i); return pPoints[0] > 0.0f && pPoints[1] == 1.0f && pPoints[2] > 0.0f; } class CPDF_CalGray final : public CPDF_ColorSpace { public: - template <typename T, typename... Args> - friend RetainPtr<T> pdfium::MakeRetain(Args&&... args); - + CONSTRUCT_VIA_MAKE_RETAIN; ~CPDF_CalGray() override; // CPDF_ColorSpace: - bool GetRGB(const float* pBuf, float* R, float* G, float* B) const override; + bool GetRGB(pdfium::span<const float> pBuf, + float* R, + float* G, + float* B) const override; uint32_t v_Load(CPDF_Document* pDoc, const CPDF_Array* pArray, std::set<const CPDF_Object*>* pVisited) override; - void TranslateImageLine(uint8_t* pDestBuf, - const uint8_t* pSrcBuf, + void TranslateImageLine(pdfium::span<uint8_t> dest_span, + pdfium::span<const uint8_t> src_span, int pixels, int image_width, int image_height, @@ -127,24 +139,25 @@ private: static constexpr float kDefaultGamma = 1.0f; - explicit CPDF_CalGray(CPDF_Document* pDoc); + CPDF_CalGray(); float m_Gamma = kDefaultGamma; - float m_WhitePoint[kBlackWhitePointCount]; - float m_BlackPoint[kBlackWhitePointCount]; + float m_WhitePoint[kBlackWhitePointCount] = {1.0f, 1.0f, 1.0f}; + float m_BlackPoint[kBlackWhitePointCount] = {0.0f, 0.0f, 0.0f}; }; class CPDF_CalRGB final : public CPDF_ColorSpace { public: - template <typename T, typename... Args> - friend RetainPtr<T> pdfium::MakeRetain(Args&&... args); - + CONSTRUCT_VIA_MAKE_RETAIN; ~CPDF_CalRGB() override; // CPDF_ColorSpace: - bool GetRGB(const float* pBuf, float* R, float* G, float* B) const override; - void TranslateImageLine(uint8_t* pDestBuf, - const uint8_t* pSrcBuf, + bool GetRGB(pdfium::span<const float> pBuf, + float* R, + float* G, + float* B) const override; + void TranslateImageLine(pdfium::span<uint8_t> dest_span, + pdfium::span<const uint8_t> src_span, int pixels, int image_width, int image_height, @@ -157,31 +170,32 @@ static constexpr size_t kGammaCount = 3; static constexpr size_t kMatrixCount = 9; - explicit CPDF_CalRGB(CPDF_Document* pDoc); + CPDF_CalRGB(); - float m_WhitePoint[kBlackWhitePointCount]; - float m_BlackPoint[kBlackWhitePointCount]; - float m_Gamma[kGammaCount]; - float m_Matrix[kMatrixCount]; - bool m_bGamma = false; - bool m_bMatrix = false; + float m_WhitePoint[kBlackWhitePointCount] = {1.0f, 1.0f, 1.0f}; + float m_BlackPoint[kBlackWhitePointCount] = {0.0f, 0.0f, 0.0f}; + float m_Gamma[kGammaCount] = {}; + float m_Matrix[kMatrixCount] = {}; + bool m_bHasGamma = false; + bool m_bHasMatrix = false; }; class CPDF_LabCS final : public CPDF_ColorSpace { public: - template <typename T, typename... Args> - friend RetainPtr<T> pdfium::MakeRetain(Args&&... args); - + CONSTRUCT_VIA_MAKE_RETAIN; ~CPDF_LabCS() override; // CPDF_ColorSpace: - bool GetRGB(const float* pBuf, float* R, float* G, float* B) const override; + bool GetRGB(pdfium::span<const float> pBuf, + float* R, + float* G, + float* B) const override; void GetDefaultValue(int iComponent, float* value, float* min, float* max) const override; - void TranslateImageLine(uint8_t* pDestBuf, - const uint8_t* pSrcBuf, + void TranslateImageLine(pdfium::span<uint8_t> dest_span, + pdfium::span<const uint8_t> src_span, int pixels, int image_width, int image_height, @@ -193,25 +207,25 @@ private: static constexpr size_t kRangesCount = 4; - explicit CPDF_LabCS(CPDF_Document* pDoc); + CPDF_LabCS(); - float m_WhitePoint[kBlackWhitePointCount]; - float m_BlackPoint[kBlackWhitePointCount]; - float m_Ranges[kRangesCount]; + float m_WhitePoint[kBlackWhitePointCount] = {1.0f, 1.0f, 1.0f}; + float m_BlackPoint[kBlackWhitePointCount] = {0.0f, 0.0f, 0.0f}; + float m_Ranges[kRangesCount] = {}; }; -class CPDF_ICCBasedCS final : public CPDF_ColorSpace { +class CPDF_ICCBasedCS final : public CPDF_BasedCS { public: - template <typename T, typename... Args> - friend RetainPtr<T> pdfium::MakeRetain(Args&&... args); - + CONSTRUCT_VIA_MAKE_RETAIN; ~CPDF_ICCBasedCS() override; // CPDF_ColorSpace: - bool GetRGB(const float* pBuf, float* R, float* G, float* B) const override; - void EnableStdConversion(bool bEnabled) override; - void TranslateImageLine(uint8_t* pDestBuf, - const uint8_t* pSrcBuf, + bool GetRGB(pdfium::span<const float> pBuf, + float* R, + float* G, + float* B) const override; + void TranslateImageLine(pdfium::span<uint8_t> dest_span, + pdfium::span<const uint8_t> src_span, int pixels, int image_width, int image_height, @@ -222,7 +236,7 @@ std::set<const CPDF_Object*>* pVisited) override; private: - explicit CPDF_ICCBasedCS(CPDF_Document* pDoc); + CPDF_ICCBasedCS(); // If no valid ICC profile or using sRGB, try looking for an alternate. bool FindAlternateProfile(CPDF_Document* pDoc, @@ -234,85 +248,57 @@ static std::vector<float> GetRanges(const CPDF_Dictionary* pDict, uint32_t nComponents); - RetainPtr<CPDF_ColorSpace> m_pAlterCS; RetainPtr<CPDF_IccProfile> m_pProfile; - mutable std::vector<uint8_t> m_pCache; + mutable DataVector<uint8_t> m_pCache; std::vector<float> m_pRanges; }; -class CPDF_IndexedCS final : public CPDF_ColorSpace { +class CPDF_SeparationCS final : public CPDF_BasedCS { public: - template <typename T, typename... Args> - friend RetainPtr<T> pdfium::MakeRetain(Args&&... args); - - ~CPDF_IndexedCS() override; - - // CPDF_ColorSpace: - bool GetRGB(const float* pBuf, float* R, float* G, float* B) const override; - void EnableStdConversion(bool bEnabled) override; - uint32_t v_Load(CPDF_Document* pDoc, - const CPDF_Array* pArray, - std::set<const CPDF_Object*>* pVisited) override; - - private: - explicit CPDF_IndexedCS(CPDF_Document* pDoc); - - RetainPtr<CPDF_ColorSpace> m_pBaseCS; - uint32_t m_nBaseComponents = 0; - int m_MaxIndex = 0; - ByteString m_Table; - std::vector<float> m_pCompMinMax; -}; - -class CPDF_SeparationCS final : public CPDF_ColorSpace { - public: - template <typename T, typename... Args> - friend RetainPtr<T> pdfium::MakeRetain(Args&&... args); - + CONSTRUCT_VIA_MAKE_RETAIN; ~CPDF_SeparationCS() override; // CPDF_ColorSpace: - bool GetRGB(const float* pBuf, float* R, float* G, float* B) const override; + bool GetRGB(pdfium::span<const float> pBuf, + float* R, + float* G, + float* B) const override; void GetDefaultValue(int iComponent, float* value, float* min, float* max) const override; - void EnableStdConversion(bool bEnabled) override; uint32_t v_Load(CPDF_Document* pDoc, const CPDF_Array* pArray, std::set<const CPDF_Object*>* pVisited) override; private: - enum { None, All, Colorant } m_Type; + CPDF_SeparationCS(); - explicit CPDF_SeparationCS(CPDF_Document* pDoc); - - RetainPtr<CPDF_ColorSpace> m_pAltCS; + bool m_IsNoneType = false; std::unique_ptr<const CPDF_Function> m_pFunc; }; -class CPDF_DeviceNCS final : public CPDF_ColorSpace { +class CPDF_DeviceNCS final : public CPDF_BasedCS { public: - template <typename T, typename... Args> - friend RetainPtr<T> pdfium::MakeRetain(Args&&... args); - + CONSTRUCT_VIA_MAKE_RETAIN; ~CPDF_DeviceNCS() override; // CPDF_ColorSpace: - bool GetRGB(const float* pBuf, float* R, float* G, float* B) const override; + bool GetRGB(pdfium::span<const float> pBuf, + float* R, + float* G, + float* B) const override; void GetDefaultValue(int iComponent, float* value, float* min, float* max) const override; - void EnableStdConversion(bool bEnabled) override; uint32_t v_Load(CPDF_Document* pDoc, const CPDF_Array* pArray, std::set<const CPDF_Object*>* pVisited) override; private: - explicit CPDF_DeviceNCS(CPDF_Document* pDoc); + CPDF_DeviceNCS(); - RetainPtr<CPDF_ColorSpace> m_pAltCS; std::unique_ptr<const CPDF_Function> m_pFunc; }; @@ -390,8 +376,8 @@ colorComponent = pdfium::clamp(colorComponent, 0.0f, 1.0f); int scale = std::max(static_cast<int>(colorComponent * 1023), 0); if (scale < 192) - return g_sRGBSamples1[scale] / 255.0f; - return g_sRGBSamples2[scale / 4 - 48] / 255.0f; + return kSRGBSamples1[scale] / 255.0f; + return kSRGBSamples2[scale / 4 - 48] / 255.0f; } void XYZ_to_sRGB(float X, float Y, float Z, float* R, float* G, float* B) { @@ -440,46 +426,36 @@ } // namespace -PatternValue::PatternValue() { - std::fill(std::begin(m_Comps), std::end(m_Comps), 0.0f); -} +PatternValue::PatternValue() = default; PatternValue::PatternValue(const PatternValue& that) = default; PatternValue::~PatternValue() = default; void PatternValue::SetComps(pdfium::span<const float> comps) { - CHECK(comps.size() <= m_Comps.size()); - std::copy(std::begin(comps), std::end(comps), std::begin(m_Comps)); + fxcrt::spancpy(pdfium::make_span(m_Comps), comps); } // static -RetainPtr<CPDF_ColorSpace> CPDF_ColorSpace::ColorspaceFromName( +RetainPtr<CPDF_ColorSpace> CPDF_ColorSpace::GetStockCSForName( const ByteString& name) { if (name == "DeviceRGB" || name == "RGB") - return CPDF_ColorSpace::GetStockCS(PDFCS_DEVICERGB); + return GetStockCS(Family::kDeviceRGB); if (name == "DeviceGray" || name == "G") - return CPDF_ColorSpace::GetStockCS(PDFCS_DEVICEGRAY); + return GetStockCS(Family::kDeviceGray); if (name == "DeviceCMYK" || name == "CMYK") - return CPDF_ColorSpace::GetStockCS(PDFCS_DEVICECMYK); + return GetStockCS(Family::kDeviceCMYK); if (name == "Pattern") - return CPDF_ColorSpace::GetStockCS(PDFCS_PATTERN); + return GetStockCS(Family::kPattern); return nullptr; } // static -RetainPtr<CPDF_ColorSpace> CPDF_ColorSpace::GetStockCS(int family) { +RetainPtr<CPDF_ColorSpace> CPDF_ColorSpace::GetStockCS(Family family) { return CPDF_PageModule::GetInstance()->GetStockCS(family); } // static -RetainPtr<CPDF_ColorSpace> CPDF_ColorSpace::Load(CPDF_Document* pDoc, - CPDF_Object* pObj) { - std::set<const CPDF_Object*> visited; - return Load(pDoc, pObj, &visited); -} - -// static RetainPtr<CPDF_ColorSpace> CPDF_ColorSpace::Load( CPDF_Document* pDoc, const CPDF_Object* pObj, @@ -487,25 +463,25 @@ if (!pObj) return nullptr; - if (pdfium::ContainsKey(*pVisited, pObj)) + if (pdfium::Contains(*pVisited, pObj)) return nullptr; - pdfium::ScopedSetInsertion<const CPDF_Object*> insertion(pVisited, pObj); + ScopedSetInsertion<const CPDF_Object*> insertion(pVisited, pObj); if (pObj->IsName()) - return ColorspaceFromName(pObj->GetString()); + return GetStockCSForName(pObj->GetString()); if (const CPDF_Stream* pStream = pObj->AsStream()) { - const CPDF_Dictionary* pDict = pStream->GetDict(); + RetainPtr<const CPDF_Dictionary> pDict = pStream->GetDict(); if (!pDict) return nullptr; - CPDF_DictionaryLocker locker(pDict); + CPDF_DictionaryLocker locker(std::move(pDict)); for (const auto& it : locker) { - CPDF_Name* pValue = ToName(it.second.Get()); + RetainPtr<const CPDF_Name> pValue = ToName(it.second); if (pValue) { RetainPtr<CPDF_ColorSpace> pRet = - ColorspaceFromName(pValue->GetString()); + GetStockCSForName(pValue->GetString()); if (pRet) return pRet; } @@ -517,44 +493,19 @@ if (!pArray || pArray->IsEmpty()) return nullptr; - const CPDF_Object* pFamilyObj = pArray->GetDirectObjectAt(0); + RetainPtr<const CPDF_Object> pFamilyObj = pArray->GetDirectObjectAt(0); if (!pFamilyObj) return nullptr; ByteString familyname = pFamilyObj->GetString(); if (pArray->size() == 1) - return ColorspaceFromName(familyname); + return GetStockCSForName(familyname); - RetainPtr<CPDF_ColorSpace> pCS; - switch (familyname.GetID()) { - case FXBSTR_ID('C', 'a', 'l', 'G'): - pCS = pdfium::MakeRetain<CPDF_CalGray>(pDoc); - break; - case FXBSTR_ID('C', 'a', 'l', 'R'): - pCS = pdfium::MakeRetain<CPDF_CalRGB>(pDoc); - break; - case FXBSTR_ID('L', 'a', 'b', 0): - pCS = pdfium::MakeRetain<CPDF_LabCS>(pDoc); - break; - case FXBSTR_ID('I', 'C', 'C', 'B'): - pCS = pdfium::MakeRetain<CPDF_ICCBasedCS>(pDoc); - break; - case FXBSTR_ID('I', 'n', 'd', 'e'): - case FXBSTR_ID('I', 0, 0, 0): - pCS = pdfium::MakeRetain<CPDF_IndexedCS>(pDoc); - break; - case FXBSTR_ID('S', 'e', 'p', 'a'): - pCS = pdfium::MakeRetain<CPDF_SeparationCS>(pDoc); - break; - case FXBSTR_ID('D', 'e', 'v', 'i'): - pCS = pdfium::MakeRetain<CPDF_DeviceNCS>(pDoc); - break; - case FXBSTR_ID('P', 'a', 't', 't'): - pCS = pdfium::MakeRetain<CPDF_PatternCS>(pDoc); - break; - default: - return nullptr; - } + RetainPtr<CPDF_ColorSpace> pCS = + CPDF_ColorSpace::AllocateColorSpace(familyname.AsStringView()); + if (!pCS) + return nullptr; + pCS->m_pArray.Reset(pArray); pCS->m_nComponents = pCS->v_Load(pDoc, pArray, pVisited); if (pCS->m_nComponents == 0) @@ -564,17 +515,42 @@ } // static -uint32_t CPDF_ColorSpace::ComponentsForFamily(int family) { +RetainPtr<CPDF_ColorSpace> CPDF_ColorSpace::AllocateColorSpace( + ByteStringView bsFamilyName) { + switch (bsFamilyName.GetID()) { + case FXBSTR_ID('C', 'a', 'l', 'G'): + return pdfium::MakeRetain<CPDF_CalGray>(); + case FXBSTR_ID('C', 'a', 'l', 'R'): + return pdfium::MakeRetain<CPDF_CalRGB>(); + case FXBSTR_ID('L', 'a', 'b', 0): + return pdfium::MakeRetain<CPDF_LabCS>(); + case FXBSTR_ID('I', 'C', 'C', 'B'): + return pdfium::MakeRetain<CPDF_ICCBasedCS>(); + case FXBSTR_ID('I', 'n', 'd', 'e'): + case FXBSTR_ID('I', 0, 0, 0): + return pdfium::MakeRetain<CPDF_IndexedCS>(); + case FXBSTR_ID('S', 'e', 'p', 'a'): + return pdfium::MakeRetain<CPDF_SeparationCS>(); + case FXBSTR_ID('D', 'e', 'v', 'i'): + return pdfium::MakeRetain<CPDF_DeviceNCS>(); + case FXBSTR_ID('P', 'a', 't', 't'): + return pdfium::MakeRetain<CPDF_PatternCS>(); + default: + return nullptr; + } +} + +// static +uint32_t CPDF_ColorSpace::ComponentsForFamily(Family family) { switch (family) { - case PDFCS_DEVICEGRAY: + case Family::kDeviceGray: return 1; - case PDFCS_DEVICERGB: + case Family::kDeviceRGB: return 3; - case PDFCS_DEVICECMYK: + case Family::kDeviceCMYK: return 4; default: - NOTREACHED(); - return 4; + NOTREACHED_NORETURN(); } } @@ -584,7 +560,7 @@ } std::vector<float> CPDF_ColorSpace::CreateBufAndSetDefaultColor() const { - ASSERT(m_Family != PDFCS_PATTERN); + DCHECK(m_Family != Family::kPattern); float min; float max; @@ -608,21 +584,23 @@ *max = 1.0f; } -void CPDF_ColorSpace::TranslateImageLine(uint8_t* dest_buf, - const uint8_t* src_buf, +void CPDF_ColorSpace::TranslateImageLine(pdfium::span<uint8_t> dest_span, + pdfium::span<const uint8_t> src_span, int pixels, int image_width, int image_height, bool bTransMask) const { + uint8_t* dest_buf = dest_span.data(); + const uint8_t* src_buf = src_span.data(); std::vector<float> src(m_nComponents); float R; float G; float B; - const int divisor = m_Family != PDFCS_INDEXED ? 255 : 1; + const int divisor = m_Family != Family::kIndexed ? 255 : 1; for (int i = 0; i < pixels; i++) { for (uint32_t j = 0; j < m_nComponents; j++) src[j] = static_cast<float>(*src_buf++) / divisor; - GetRGB(src.data(), &R, &G, &B); + GetRGB(src, &R, &G, &B); *dest_buf++ = static_cast<int32_t>(B * 255); *dest_buf++ = static_cast<int32_t>(G * 255); *dest_buf++ = static_cast<int32_t>(R * 255); @@ -637,135 +615,126 @@ } bool CPDF_ColorSpace::IsNormal() const { - return GetFamily() == PDFCS_DEVICEGRAY || GetFamily() == PDFCS_DEVICERGB || - GetFamily() == PDFCS_DEVICECMYK || GetFamily() == PDFCS_CALGRAY || - GetFamily() == PDFCS_CALRGB; -} - -CPDF_PatternCS* CPDF_ColorSpace::AsPatternCS() { - NOTREACHED(); - return nullptr; + return GetFamily() == Family::kDeviceGray || + GetFamily() == Family::kDeviceRGB || + GetFamily() == Family::kDeviceCMYK || + GetFamily() == Family::kCalGray || GetFamily() == Family::kCalRGB; } const CPDF_PatternCS* CPDF_ColorSpace::AsPatternCS() const { - NOTREACHED(); return nullptr; } -bool CPDF_ColorSpace::GetPatternRGB(const PatternValue& value, - float* R, - float* G, - float* B) const { - NOTREACHED(); - return false; +const CPDF_IndexedCS* CPDF_ColorSpace::AsIndexedCS() const { + return nullptr; } -CPDF_ColorSpace::CPDF_ColorSpace(CPDF_Document* pDoc, int family) - : m_pDocument(pDoc), m_Family(family) {} +CPDF_ColorSpace::CPDF_ColorSpace(Family family) : m_Family(family) {} CPDF_ColorSpace::~CPDF_ColorSpace() = default; void CPDF_ColorSpace::SetComponentsForStockCS(uint32_t nComponents) { - ASSERT(!m_pDocument); // Stock colorspace is not associated with a document. m_nComponents = nComponents; } -CPDF_CalGray::CPDF_CalGray(CPDF_Document* pDoc) - : CPDF_ColorSpace(pDoc, PDFCS_CALGRAY) {} +CPDF_CalGray::CPDF_CalGray() : CPDF_ColorSpace(Family::kCalGray) {} CPDF_CalGray::~CPDF_CalGray() = default; uint32_t CPDF_CalGray::v_Load(CPDF_Document* pDoc, const CPDF_Array* pArray, std::set<const CPDF_Object*>* pVisited) { - const CPDF_Dictionary* pDict = pArray->GetDictAt(1); + RetainPtr<const CPDF_Dictionary> pDict = pArray->GetDictAt(1); if (!pDict) return 0; - if (!GetWhitePoint(pDict, m_WhitePoint)) + if (!GetWhitePoint(pDict.Get(), m_WhitePoint)) return 0; - GetBlackPoint(pDict, m_BlackPoint); + GetBlackPoint(pDict.Get(), m_BlackPoint); - m_Gamma = pDict->GetNumberFor("Gamma"); + m_Gamma = pDict->GetFloatFor("Gamma"); if (m_Gamma == 0) m_Gamma = kDefaultGamma; return 1; } -bool CPDF_CalGray::GetRGB(const float* pBuf, +bool CPDF_CalGray::GetRGB(pdfium::span<const float> pBuf, float* R, float* G, float* B) const { - *R = *pBuf; - *G = *pBuf; - *B = *pBuf; + *R = pBuf[0]; + *G = pBuf[0]; + *B = pBuf[0]; return true; } -void CPDF_CalGray::TranslateImageLine(uint8_t* pDestBuf, - const uint8_t* pSrcBuf, +void CPDF_CalGray::TranslateImageLine(pdfium::span<uint8_t> dest_span, + pdfium::span<const uint8_t> src_span, int pixels, int image_width, int image_height, bool bTransMask) const { + uint8_t* pDestBuf = dest_span.data(); + const uint8_t* pSrcBuf = src_span.data(); for (int i = 0; i < pixels; i++) { - *pDestBuf++ = pSrcBuf[i]; - *pDestBuf++ = pSrcBuf[i]; - *pDestBuf++ = pSrcBuf[i]; + // Compiler can not conclude that src/dest don't overlap. + const uint8_t pix = pSrcBuf[i]; + *pDestBuf++ = pix; + *pDestBuf++ = pix; + *pDestBuf++ = pix; } } -CPDF_CalRGB::CPDF_CalRGB(CPDF_Document* pDoc) - : CPDF_ColorSpace(pDoc, PDFCS_CALRGB) {} +CPDF_CalRGB::CPDF_CalRGB() : CPDF_ColorSpace(Family::kCalRGB) {} CPDF_CalRGB::~CPDF_CalRGB() = default; uint32_t CPDF_CalRGB::v_Load(CPDF_Document* pDoc, const CPDF_Array* pArray, std::set<const CPDF_Object*>* pVisited) { - const CPDF_Dictionary* pDict = pArray->GetDictAt(1); + RetainPtr<const CPDF_Dictionary> pDict = pArray->GetDictAt(1); if (!pDict) return 0; - if (!GetWhitePoint(pDict, m_WhitePoint)) + if (!GetWhitePoint(pDict.Get(), m_WhitePoint)) return 0; - GetBlackPoint(pDict, m_BlackPoint); + GetBlackPoint(pDict.Get(), m_BlackPoint); - const CPDF_Array* pParam = pDict->GetArrayFor("Gamma"); - if (pParam) { - m_bGamma = true; - for (size_t i = 0; i < FX_ArraySize(m_Gamma); ++i) - m_Gamma[i] = pParam->GetNumberAt(i); + RetainPtr<const CPDF_Array> pGamma = pDict->GetArrayFor("Gamma"); + if (pGamma) { + m_bHasGamma = true; + for (size_t i = 0; i < std::size(m_Gamma); ++i) + m_Gamma[i] = pGamma->GetFloatAt(i); } - pParam = pDict->GetArrayFor("Matrix"); - if (pParam) { - m_bMatrix = true; - for (size_t i = 0; i < FX_ArraySize(m_Matrix); ++i) - m_Matrix[i] = pParam->GetNumberAt(i); + RetainPtr<const CPDF_Array> pMatrix = pDict->GetArrayFor("Matrix"); + if (pMatrix) { + m_bHasMatrix = true; + for (size_t i = 0; i < std::size(m_Matrix); ++i) + m_Matrix[i] = pMatrix->GetFloatAt(i); } return 3; } -bool CPDF_CalRGB::GetRGB(const float* pBuf, +bool CPDF_CalRGB::GetRGB(pdfium::span<const float> pBuf, float* R, float* G, float* B) const { float A_ = pBuf[0]; float B_ = pBuf[1]; float C_ = pBuf[2]; - if (m_bGamma) { - A_ = FXSYS_pow(A_, m_Gamma[0]); - B_ = FXSYS_pow(B_, m_Gamma[1]); - C_ = FXSYS_pow(C_, m_Gamma[2]); + if (m_bHasGamma) { + A_ = powf(A_, m_Gamma[0]); + B_ = powf(B_, m_Gamma[1]); + C_ = powf(C_, m_Gamma[2]); } float X; float Y; float Z; - if (m_bMatrix) { + if (m_bHasMatrix) { X = m_Matrix[0] * A_ + m_Matrix[3] * B_ + m_Matrix[6] * C_; Y = m_Matrix[1] * A_ + m_Matrix[4] * B_ + m_Matrix[7] * C_; Z = m_Matrix[2] * A_ + m_Matrix[5] * B_ + m_Matrix[8] * C_; @@ -779,34 +748,37 @@ return true; } -void CPDF_CalRGB::TranslateImageLine(uint8_t* pDestBuf, - const uint8_t* pSrcBuf, +void CPDF_CalRGB::TranslateImageLine(pdfium::span<uint8_t> dest_span, + pdfium::span<const uint8_t> src_span, int pixels, int image_width, int image_height, bool bTransMask) const { - if (bTransMask) { - float Cal[3]; - float R; - float G; - float B; - for (int i = 0; i < pixels; i++) { - Cal[0] = static_cast<float>(pSrcBuf[2]) / 255; - Cal[1] = static_cast<float>(pSrcBuf[1]) / 255; - Cal[2] = static_cast<float>(pSrcBuf[0]) / 255; - GetRGB(Cal, &R, &G, &B); - pDestBuf[0] = FXSYS_roundf(B * 255); - pDestBuf[1] = FXSYS_roundf(G * 255); - pDestBuf[2] = FXSYS_roundf(R * 255); - pSrcBuf += 3; - pDestBuf += 3; - } + uint8_t* pDestBuf = dest_span.data(); + const uint8_t* pSrcBuf = src_span.data(); + if (!bTransMask) { + fxcodec::ReverseRGB(pDestBuf, pSrcBuf, pixels); + return; } - fxcodec::ReverseRGB(pDestBuf, pSrcBuf, pixels); + + float Cal[3]; + float R; + float G; + float B; + for (int i = 0; i < pixels; i++) { + Cal[0] = static_cast<float>(pSrcBuf[2]) / 255; + Cal[1] = static_cast<float>(pSrcBuf[1]) / 255; + Cal[2] = static_cast<float>(pSrcBuf[0]) / 255; + GetRGB(Cal, &R, &G, &B); + pDestBuf[0] = FXSYS_roundf(B * 255); + pDestBuf[1] = FXSYS_roundf(G * 255); + pDestBuf[2] = FXSYS_roundf(R * 255); + pSrcBuf += 3; + pDestBuf += 3; + } } -CPDF_LabCS::CPDF_LabCS(CPDF_Document* pDoc) - : CPDF_ColorSpace(pDoc, PDFCS_LAB) {} +CPDF_LabCS::CPDF_LabCS() : CPDF_ColorSpace(Family::kLab) {} CPDF_LabCS::~CPDF_LabCS() = default; @@ -814,42 +786,50 @@ float* value, float* min, float* max) const { - ASSERT(iComponent < 3); - if (iComponent == 0) { - *min = 0.0f; - *max = 100 * 1.0f; - *value = 0.0f; - return; + DCHECK_LT(iComponent, 3); + + if (iComponent > 0) { + float range_min = m_Ranges[iComponent * 2 - 2]; + float range_max = m_Ranges[iComponent * 2 - 1]; + if (range_min <= range_max) { + *min = range_min; + *max = range_max; + *value = pdfium::clamp(0.0f, *min, *max); + return; + } } - *min = m_Ranges[iComponent * 2 - 2]; - *max = m_Ranges[iComponent * 2 - 1]; - *value = pdfium::clamp(0.0f, *min, *max); + *min = 0.0f; + *max = 100.0f; + *value = 0.0f; } uint32_t CPDF_LabCS::v_Load(CPDF_Document* pDoc, const CPDF_Array* pArray, std::set<const CPDF_Object*>* pVisited) { - const CPDF_Dictionary* pDict = pArray->GetDictAt(1); + RetainPtr<const CPDF_Dictionary> pDict = pArray->GetDictAt(1); if (!pDict) return 0; - if (!GetWhitePoint(pDict, m_WhitePoint)) + if (!GetWhitePoint(pDict.Get(), m_WhitePoint)) return 0; - GetBlackPoint(pDict, m_BlackPoint); + GetBlackPoint(pDict.Get(), m_BlackPoint); - const CPDF_Array* pParam = pDict->GetArrayFor("Range"); + RetainPtr<const CPDF_Array> pParam = pDict->GetArrayFor("Range"); static constexpr float kDefaultRanges[kRangesCount] = {-100.0f, 100.0f, -100.0f, 100.0f}; - static_assert(FX_ArraySize(kDefaultRanges) == FX_ArraySize(m_Ranges), + static_assert(std::size(kDefaultRanges) == std::extent<decltype(m_Ranges)>(), "Range size mismatch"); - for (size_t i = 0; i < FX_ArraySize(kDefaultRanges); ++i) - m_Ranges[i] = pParam ? pParam->GetNumberAt(i) : kDefaultRanges[i]; + for (size_t i = 0; i < std::size(kDefaultRanges); ++i) + m_Ranges[i] = pParam ? pParam->GetFloatAt(i) : kDefaultRanges[i]; return 3; } -bool CPDF_LabCS::GetRGB(const float* pBuf, float* R, float* G, float* B) const { +bool CPDF_LabCS::GetRGB(pdfium::span<const float> pBuf, + float* R, + float* G, + float* B) const { float Lstar = pBuf[0]; float astar = pBuf[1]; float bstar = pBuf[2]; @@ -878,12 +858,14 @@ return true; } -void CPDF_LabCS::TranslateImageLine(uint8_t* pDestBuf, - const uint8_t* pSrcBuf, +void CPDF_LabCS::TranslateImageLine(pdfium::span<uint8_t> dest_span, + pdfium::span<const uint8_t> src_span, int pixels, int image_width, int image_height, bool bTransMask) const { + uint8_t* pDestBuf = dest_span.data(); + const uint8_t* pSrcBuf = src_span.data(); for (int i = 0; i < pixels; i++) { float lab[3]; lab[0] = pSrcBuf[0] * 100 / 255.0f; @@ -902,22 +884,21 @@ } } -CPDF_ICCBasedCS::CPDF_ICCBasedCS(CPDF_Document* pDoc) - : CPDF_ColorSpace(pDoc, PDFCS_ICCBASED) {} +CPDF_ICCBasedCS::CPDF_ICCBasedCS() : CPDF_BasedCS(Family::kICCBased) {} CPDF_ICCBasedCS::~CPDF_ICCBasedCS() = default; uint32_t CPDF_ICCBasedCS::v_Load(CPDF_Document* pDoc, const CPDF_Array* pArray, std::set<const CPDF_Object*>* pVisited) { - const CPDF_Stream* pStream = pArray->GetStreamAt(1); + RetainPtr<const CPDF_Stream> pStream = pArray->GetStreamAt(1); if (!pStream) return 0; // The PDF 1.7 spec says the number of components must be valid. While some // PDF viewers tolerate invalid values, Acrobat does not, so be consistent // with Acrobat and reject bad values. - const CPDF_Dictionary* pDict = pStream->GetDict(); + RetainPtr<const CPDF_Dictionary> pDict = pStream->GetDict(); int32_t nDictComponents = pDict ? pDict->GetIntegerFor("N") : 0; if (!IsValidIccComponents(nDictComponents)) return 0; @@ -938,39 +919,38 @@ // SRGB, a profile PDFium recognizes but does not support well, then try the // alternate profile. if (!m_pProfile->IsSupported() && - !FindAlternateProfile(pDoc, pDict, pVisited, nComponents)) { + !FindAlternateProfile(pDoc, pDict.Get(), pVisited, nComponents)) { // If there is no alternate profile, use a stock profile as mentioned in // the PDF 1.7 spec in table 4.16 in the "Alternate" key description. - ASSERT(!m_pAlterCS); - m_pAlterCS = GetStockAlternateProfile(nComponents); + DCHECK(!m_pBaseCS); + m_pBaseCS = GetStockAlternateProfile(nComponents); } - m_pRanges = GetRanges(pDict, nComponents); + m_pRanges = GetRanges(pDict.Get(), nComponents); return nComponents; } -bool CPDF_ICCBasedCS::GetRGB(const float* pBuf, +bool CPDF_ICCBasedCS::GetRGB(pdfium::span<const float> pBuf, float* R, float* G, float* B) const { - ASSERT(m_pProfile); + DCHECK(m_pProfile); if (m_pProfile->IsSRGB()) { *R = pBuf[0]; *G = pBuf[1]; *B = pBuf[2]; return true; } - if (m_pProfile->transform()) { + if (m_pProfile->IsSupported()) { float rgb[3]; - IccModule::Translate(m_pProfile->transform(), CountComponents(), pBuf, rgb); + m_pProfile->Translate(pBuf.first(CountComponents()), rgb); *R = rgb[0]; *G = rgb[1]; *B = rgb[2]; return true; } - - if (m_pAlterCS) - return m_pAlterCS->GetRGB(pBuf, R, G, B); + if (m_pBaseCS) + return m_pBaseCS->GetRGB(pBuf, R, G, B); *R = 0.0f; *G = 0.0f; @@ -978,33 +958,27 @@ return true; } -void CPDF_ICCBasedCS::EnableStdConversion(bool bEnabled) { - CPDF_ColorSpace::EnableStdConversion(bEnabled); - if (m_pAlterCS) - m_pAlterCS->EnableStdConversion(bEnabled); -} - -void CPDF_ICCBasedCS::TranslateImageLine(uint8_t* pDestBuf, - const uint8_t* pSrcBuf, +void CPDF_ICCBasedCS::TranslateImageLine(pdfium::span<uint8_t> dest_span, + pdfium::span<const uint8_t> src_span, int pixels, int image_width, int image_height, bool bTransMask) const { if (m_pProfile->IsSRGB()) { - fxcodec::ReverseRGB(pDestBuf, pSrcBuf, pixels); + fxcodec::ReverseRGB(dest_span.data(), src_span.data(), pixels); return; } - if (!m_pProfile->transform()) { - if (m_pAlterCS) { - m_pAlterCS->TranslateImageLine(pDestBuf, pSrcBuf, pixels, image_width, - image_height, false); + if (!m_pProfile->IsSupported()) { + if (m_pBaseCS) { + m_pBaseCS->TranslateImageLine(dest_span, src_span, pixels, image_width, + image_height, false); } return; } // |nMaxColors| will not overflow since |nComponents| is limited in size. const uint32_t nComponents = CountComponents(); - ASSERT(IsValidIccComponents(nComponents)); + DCHECK(IsValidIccComponents(nComponents)); int nMaxColors = 1; for (uint32_t i = 0; i < nComponents; i++) nMaxColors *= 52; @@ -1016,15 +990,13 @@ if (nPixelCount.IsValid()) bTranslate = nPixelCount.ValueOrDie() < nMaxColors * 3 / 2; } - if (bTranslate) { - IccModule::TranslateScanline(m_pProfile->transform(), pDestBuf, pSrcBuf, - pixels); + if (bTranslate && m_pProfile->IsSupported()) { + m_pProfile->TranslateScanline(dest_span, src_span, pixels); return; } - if (m_pCache.empty()) { - m_pCache = pdfium::Vector2D<uint8_t>(nMaxColors, 3); - auto temp_src = pdfium::Vector2D<uint8_t>(nMaxColors, nComponents); + m_pCache.resize(Fx2DSizeOrDie(nMaxColors, 3)); + DataVector<uint8_t> temp_src(Fx2DSizeOrDie(nMaxColors, nComponents)); size_t src_index = 0; for (int i = 0; i < nMaxColors; i++) { uint32_t color = i; @@ -1035,9 +1007,12 @@ order /= 52; } } - IccModule::TranslateScanline(m_pProfile->transform(), m_pCache.data(), - temp_src.data(), nMaxColors); + if (m_pProfile->IsSupported()) { + m_pProfile->TranslateScanline(m_pCache, temp_src, nMaxColors); + } } + uint8_t* pDestBuf = dest_span.data(); + const uint8_t* pSrcBuf = src_span.data(); for (int i = 0; i < pixels; i++) { int index = 0; for (uint32_t c = 0; c < nComponents; c++) { @@ -1054,10 +1029,10 @@ bool CPDF_ICCBasedCS::IsNormal() const { if (m_pProfile->IsSRGB()) return true; - if (m_pProfile->transform()) - return m_pProfile->transform()->IsNormal(); - if (m_pAlterCS) - return m_pAlterCS->IsNormal(); + if (m_pProfile->IsSupported()) + return m_pProfile->IsNormal(); + if (m_pBaseCS) + return m_pBaseCS->IsNormal(); return false; } @@ -1066,21 +1041,22 @@ const CPDF_Dictionary* pDict, std::set<const CPDF_Object*>* pVisited, uint32_t nExpectedComponents) { - const CPDF_Object* pAlterCSObj = pDict->GetDirectObjectFor("Alternate"); + RetainPtr<const CPDF_Object> pAlterCSObj = + pDict->GetDirectObjectFor("Alternate"); if (!pAlterCSObj) return false; - auto pAlterCS = CPDF_ColorSpace::Load(pDoc, pAlterCSObj, pVisited); + auto pAlterCS = CPDF_ColorSpace::Load(pDoc, pAlterCSObj.Get(), pVisited); if (!pAlterCS) return false; - if (pAlterCS->GetFamily() == PDFCS_PATTERN) + if (pAlterCS->GetFamily() == Family::kPattern) return false; if (pAlterCS->CountComponents() != nExpectedComponents) return false; - m_pAlterCS = std::move(pAlterCS); + m_pBaseCS = std::move(pAlterCS); return true; } @@ -1088,122 +1064,32 @@ RetainPtr<CPDF_ColorSpace> CPDF_ICCBasedCS::GetStockAlternateProfile( uint32_t nComponents) { if (nComponents == 1) - return GetStockCS(PDFCS_DEVICEGRAY); + return GetStockCS(Family::kDeviceGray); if (nComponents == 3) - return GetStockCS(PDFCS_DEVICERGB); + return GetStockCS(Family::kDeviceRGB); if (nComponents == 4) - return GetStockCS(PDFCS_DEVICECMYK); - NOTREACHED(); - return nullptr; + return GetStockCS(Family::kDeviceCMYK); + NOTREACHED_NORETURN(); } // static std::vector<float> CPDF_ICCBasedCS::GetRanges(const CPDF_Dictionary* pDict, uint32_t nComponents) { - ASSERT(IsValidIccComponents(nComponents)); + DCHECK(IsValidIccComponents(nComponents)); + RetainPtr<const CPDF_Array> pRanges = pDict->GetArrayFor("Range"); + if (pRanges && pRanges->size() >= nComponents * 2) + return ReadArrayElementsToVector(pRanges.Get(), nComponents * 2); std::vector<float> ranges; - const CPDF_Array* pRanges = pDict->GetArrayFor("Range"); - if (pRanges) { - ranges = ReadArrayElementsToVector(pRanges, nComponents * 2); - } else { - ranges.reserve(nComponents * 2); - for (uint32_t i = 0; i < nComponents; i++) { - ranges.push_back(0.0f); - ranges.push_back(1.0f); - } + ranges.reserve(nComponents * 2); + for (uint32_t i = 0; i < nComponents; i++) { + ranges.push_back(0.0f); + ranges.push_back(1.0f); } return ranges; } -CPDF_IndexedCS::CPDF_IndexedCS(CPDF_Document* pDoc) - : CPDF_ColorSpace(pDoc, PDFCS_INDEXED) {} - -CPDF_IndexedCS::~CPDF_IndexedCS() = default; - -uint32_t CPDF_IndexedCS::v_Load(CPDF_Document* pDoc, - const CPDF_Array* pArray, - std::set<const CPDF_Object*>* pVisited) { - if (pArray->size() < 4) - return 0; - - const CPDF_Object* pBaseObj = pArray->GetDirectObjectAt(1); - if (pBaseObj == m_pArray) - return 0; - - auto* pDocPageData = CPDF_DocPageData::FromDocument(pDoc); - m_pBaseCS = pDocPageData->GetColorSpaceGuarded(pBaseObj, nullptr, pVisited); - if (!m_pBaseCS) - return 0; - - // The base color space cannot be a Pattern or Indexed space, according to the - // PDF 1.7 spec, page 263. - int family = m_pBaseCS->GetFamily(); - if (family == PDFCS_INDEXED || family == PDFCS_PATTERN) - return 0; - - m_nBaseComponents = m_pBaseCS->CountComponents(); - m_pCompMinMax = pdfium::Vector2D<float>(m_nBaseComponents, 2); - float defvalue; - for (uint32_t i = 0; i < m_nBaseComponents; i++) { - m_pBaseCS->GetDefaultValue(i, &defvalue, &m_pCompMinMax[i * 2], - &m_pCompMinMax[i * 2 + 1]); - m_pCompMinMax[i * 2 + 1] -= m_pCompMinMax[i * 2]; - } - m_MaxIndex = pArray->GetIntegerAt(2); - - const CPDF_Object* pTableObj = pArray->GetDirectObjectAt(3); - if (!pTableObj) - return 0; - - if (const CPDF_String* pString = pTableObj->AsString()) { - m_Table = pString->GetString(); - } else if (const CPDF_Stream* pStream = pTableObj->AsStream()) { - auto pAcc = pdfium::MakeRetain<CPDF_StreamAcc>(pStream); - pAcc->LoadAllDataFiltered(); - m_Table = ByteStringView(pAcc->GetSpan()); - } - return 1; -} - -bool CPDF_IndexedCS::GetRGB(const float* pBuf, - float* R, - float* G, - float* B) const { - int32_t index = static_cast<int32_t>(*pBuf); - if (index < 0 || index > m_MaxIndex) - return false; - - if (m_nBaseComponents) { - FX_SAFE_SIZE_T length = index; - length += 1; - length *= m_nBaseComponents; - if (!length.IsValid() || length.ValueOrDie() > m_Table.GetLength()) { - *R = 0; - *G = 0; - *B = 0; - return false; - } - } - std::vector<float> comps(m_nBaseComponents); - const uint8_t* pTable = m_Table.raw_str(); - for (uint32_t i = 0; i < m_nBaseComponents; ++i) { - comps[i] = - m_pCompMinMax[i * 2] + - m_pCompMinMax[i * 2 + 1] * pTable[index * m_nBaseComponents + i] / 255; - } - ASSERT(m_nBaseComponents == m_pBaseCS->CountComponents()); - return m_pBaseCS->GetRGB(comps.data(), R, G, B); -} - -void CPDF_IndexedCS::EnableStdConversion(bool bEnabled) { - CPDF_ColorSpace::EnableStdConversion(bEnabled); - if (m_pBaseCS) - m_pBaseCS->EnableStdConversion(bEnabled); -} - -CPDF_SeparationCS::CPDF_SeparationCS(CPDF_Document* pDoc) - : CPDF_ColorSpace(pDoc, PDFCS_SEPARATION) {} +CPDF_SeparationCS::CPDF_SeparationCS() : CPDF_BasedCS(Family::kSeparation) {} CPDF_SeparationCS::~CPDF_SeparationCS() = default; @@ -1219,74 +1105,64 @@ uint32_t CPDF_SeparationCS::v_Load(CPDF_Document* pDoc, const CPDF_Array* pArray, std::set<const CPDF_Object*>* pVisited) { - ByteString name = pArray->GetStringAt(1); - if (name == "None") { - m_Type = None; + m_IsNoneType = pArray->GetByteStringAt(1) == "None"; + if (m_IsNoneType) return 1; - } - m_Type = Colorant; - const CPDF_Object* pAltCS = pArray->GetDirectObjectAt(2); - if (pAltCS == m_pArray) + RetainPtr<const CPDF_Object> pAltArray = pArray->GetDirectObjectAt(2); + if (HasSameArray(pAltArray.Get())) return 0; - m_pAltCS = Load(pDoc, pAltCS, pVisited); - if (!m_pAltCS) + m_pBaseCS = Load(pDoc, pAltArray.Get(), pVisited); + if (!m_pBaseCS) return 0; - if (m_pAltCS->IsSpecial()) + if (m_pBaseCS->IsSpecial()) return 0; - const CPDF_Object* pFuncObj = pArray->GetDirectObjectAt(3); + RetainPtr<const CPDF_Object> pFuncObj = pArray->GetDirectObjectAt(3); if (pFuncObj && !pFuncObj->IsName()) { - auto pFunc = CPDF_Function::Load(pFuncObj); - if (pFunc && pFunc->CountOutputs() >= m_pAltCS->CountComponents()) + auto pFunc = CPDF_Function::Load(std::move(pFuncObj)); + if (pFunc && pFunc->CountOutputs() >= m_pBaseCS->CountComponents()) m_pFunc = std::move(pFunc); } return 1; } -bool CPDF_SeparationCS::GetRGB(const float* pBuf, +bool CPDF_SeparationCS::GetRGB(pdfium::span<const float> pBuf, float* R, float* G, float* B) const { - if (m_Type == None) + if (m_IsNoneType) return false; if (!m_pFunc) { - if (!m_pAltCS) + if (!m_pBaseCS) return false; - int nComps = m_pAltCS->CountComponents(); + int nComps = m_pBaseCS->CountComponents(); std::vector<float> results(nComps); for (int i = 0; i < nComps; i++) - results[i] = *pBuf; - return m_pAltCS->GetRGB(results.data(), R, G, B); + results[i] = pBuf[0]; + return m_pBaseCS->GetRGB(results, R, G, B); } // Using at least 16 elements due to the call m_pAltCS->GetRGB() below. std::vector<float> results(std::max(m_pFunc->CountOutputs(), 16u)); - int nresults = 0; - if (!m_pFunc->Call(pBuf, 1, results.data(), &nresults) || nresults == 0) + uint32_t nresults = m_pFunc->Call(pBuf.first(1), results).value_or(0); + if (nresults == 0) return false; - if (m_pAltCS) - return m_pAltCS->GetRGB(results.data(), R, G, B); + if (m_pBaseCS) + return m_pBaseCS->GetRGB(results, R, G, B); - R = 0; - G = 0; - B = 0; + *R = 0.0f; + *G = 0.0f; + *B = 0.0f; return false; } -void CPDF_SeparationCS::EnableStdConversion(bool bEnabled) { - CPDF_ColorSpace::EnableStdConversion(bEnabled); - if (m_pAltCS) - m_pAltCS->EnableStdConversion(bEnabled); -} - -CPDF_DeviceNCS::CPDF_DeviceNCS(CPDF_Document* pDoc) - : CPDF_ColorSpace(pDoc, PDFCS_DEVICEN) {} +CPDF_DeviceNCS::CPDF_DeviceNCS() : CPDF_BasedCS(Family::kDeviceN) {} CPDF_DeviceNCS::~CPDF_DeviceNCS() = default; @@ -1302,29 +1178,29 @@ uint32_t CPDF_DeviceNCS::v_Load(CPDF_Document* pDoc, const CPDF_Array* pArray, std::set<const CPDF_Object*>* pVisited) { - const CPDF_Array* pObj = ToArray(pArray->GetDirectObjectAt(1)); + RetainPtr<const CPDF_Array> pObj = ToArray(pArray->GetDirectObjectAt(1)); if (!pObj) return 0; - const CPDF_Object* pAltCS = pArray->GetDirectObjectAt(2); - if (!pAltCS || pAltCS == m_pArray) + RetainPtr<const CPDF_Object> pAltCS = pArray->GetDirectObjectAt(2); + if (!pAltCS || HasSameArray(pAltCS.Get())) return 0; - m_pAltCS = Load(pDoc, pAltCS, pVisited); + m_pBaseCS = Load(pDoc, pAltCS.Get(), pVisited); m_pFunc = CPDF_Function::Load(pArray->GetDirectObjectAt(3)); - if (!m_pAltCS || !m_pFunc) + if (!m_pBaseCS || !m_pFunc) return 0; - if (m_pAltCS->IsSpecial()) + if (m_pBaseCS->IsSpecial()) return 0; - if (m_pFunc->CountOutputs() < m_pAltCS->CountComponents()) + if (m_pFunc->CountOutputs() < m_pBaseCS->CountComponents()) return 0; - return pObj->size(); + return fxcrt::CollectionSize<uint32_t>(*pObj); } -bool CPDF_DeviceNCS::GetRGB(const float* pBuf, +bool CPDF_DeviceNCS::GetRGB(pdfium::span<const float> pBuf, float* R, float* G, float* B) const { @@ -1333,18 +1209,12 @@ // Using at least 16 elements due to the call m_pAltCS->GetRGB() below. std::vector<float> results(std::max(m_pFunc->CountOutputs(), 16u)); - int nresults = 0; - if (!m_pFunc->Call(pBuf, CountComponents(), results.data(), &nresults) || - nresults == 0) { + uint32_t nresults = + m_pFunc->Call(pBuf.first(CountComponents()), pdfium::make_span(results)) + .value_or(0); + + if (nresults == 0) return false; - } - return m_pAltCS->GetRGB(results.data(), R, G, B); -} - -void CPDF_DeviceNCS::EnableStdConversion(bool bEnabled) { - CPDF_ColorSpace::EnableStdConversion(bEnabled); - if (m_pAltCS) { - m_pAltCS->EnableStdConversion(bEnabled); - } + return m_pBaseCS->GetRGB(results, R, G, B); }
diff --git a/core/fpdfapi/page/cpdf_colorspace.h b/core/fpdfapi/page/cpdf_colorspace.h index 75928d2..23253c8 100644 --- a/core/fpdfapi/page/cpdf_colorspace.h +++ b/core/fpdfapi/page/cpdf_colorspace.h
@@ -1,4 +1,4 @@ -// Copyright 2016 PDFium Authors. All rights reserved. +// Copyright 2016 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -7,34 +7,25 @@ #ifndef CORE_FPDFAPI_PAGE_CPDF_COLORSPACE_H_ #define CORE_FPDFAPI_PAGE_CPDF_COLORSPACE_H_ +#include <stddef.h> +#include <stdint.h> + #include <array> -#include <memory> #include <set> +#include <utility> #include <vector> #include "core/fpdfapi/page/cpdf_pattern.h" -#include "core/fxcrt/fx_string.h" -#include "core/fxcrt/fx_system.h" +#include "core/fpdfapi/parser/cpdf_array.h" +#include "core/fpdfapi/parser/cpdf_object.h" +#include "core/fxcrt/bytestring.h" #include "core/fxcrt/observed_ptr.h" #include "core/fxcrt/retain_ptr.h" #include "core/fxcrt/unowned_ptr.h" #include "third_party/base/span.h" -#define PDFCS_DEVICEGRAY 1 -#define PDFCS_DEVICERGB 2 -#define PDFCS_DEVICECMYK 3 -#define PDFCS_CALGRAY 4 -#define PDFCS_CALRGB 5 -#define PDFCS_LAB 6 -#define PDFCS_ICCBASED 7 -#define PDFCS_SEPARATION 8 -#define PDFCS_DEVICEN 9 -#define PDFCS_INDEXED 10 -#define PDFCS_PATTERN 11 - -class CPDF_Array; class CPDF_Document; -class CPDF_Object; +class CPDF_IndexedCS; class CPDF_PatternCS; constexpr size_t kMaxPatternColorComps = 16; @@ -51,43 +42,60 @@ return {m_Comps.data(), m_Comps.size()}; } - CPDF_Pattern* GetPattern() const { return m_pRetainedPattern.Get(); } - void SetPattern(const RetainPtr<CPDF_Pattern>& pPattern) { - m_pRetainedPattern = pPattern; + RetainPtr<CPDF_Pattern> GetPattern() const { return m_pRetainedPattern; } + void SetPattern(RetainPtr<CPDF_Pattern> pPattern) { + m_pRetainedPattern = std::move(pPattern); } private: RetainPtr<CPDF_Pattern> m_pRetainedPattern; - std::array<float, kMaxPatternColorComps> m_Comps; + std::array<float, kMaxPatternColorComps> m_Comps{}; }; class CPDF_ColorSpace : public Retainable, public Observable { public: - static RetainPtr<CPDF_ColorSpace> GetStockCS(int Family); - static RetainPtr<CPDF_ColorSpace> ColorspaceFromName(const ByteString& name); - static RetainPtr<CPDF_ColorSpace> Load(CPDF_Document* pDoc, - CPDF_Object* pObj); + enum class Family { + kUnknown = 0, + kDeviceGray = 1, + kDeviceRGB = 2, + kDeviceCMYK = 3, + kCalGray = 4, + kCalRGB = 5, + kLab = 6, + kICCBased = 7, + kSeparation = 8, + kDeviceN = 9, + kIndexed = 10, + kPattern = 11, + }; + + static RetainPtr<CPDF_ColorSpace> GetStockCS(Family family); + static RetainPtr<CPDF_ColorSpace> GetStockCSForName(const ByteString& name); static RetainPtr<CPDF_ColorSpace> Load( CPDF_Document* pDoc, const CPDF_Object* pObj, std::set<const CPDF_Object*>* pVisited); - static uint32_t ComponentsForFamily(int family); - static bool IsValidIccComponents(int components); - const CPDF_Array* GetArray() const { return m_pArray.Get(); } - CPDF_Document* GetDocument() const { return m_pDocument.Get(); } + static RetainPtr<CPDF_ColorSpace> AllocateColorSpaceForID( + CPDF_Document* pDocument, + uint32_t family_id); + + static uint32_t ComponentsForFamily(Family family); + static bool IsValidIccComponents(int components); // Should only be called if this colorspace is not a pattern. std::vector<float> CreateBufAndSetDefaultColor() const; uint32_t CountComponents() const; - int GetFamily() const { return m_Family; } + Family GetFamily() const { return m_Family; } bool IsSpecial() const { - return GetFamily() == PDFCS_SEPARATION || GetFamily() == PDFCS_DEVICEN || - GetFamily() == PDFCS_INDEXED || GetFamily() == PDFCS_PATTERN; + return GetFamily() == Family::kSeparation || + GetFamily() == Family::kDeviceN || GetFamily() == Family::kIndexed || + GetFamily() == Family::kPattern; } - virtual bool GetRGB(const float* pBuf, + // Use CPDF_Pattern::GetPatternRGB() instead of GetRGB() for patterns. + virtual bool GetRGB(pdfium::span<const float> pBuf, float* R, float* G, float* B) const = 0; @@ -96,8 +104,9 @@ float* value, float* min, float* max) const; - virtual void TranslateImageLine(uint8_t* dest_buf, - const uint8_t* src_buf, + + virtual void TranslateImageLine(pdfium::span<uint8_t> dest_span, + pdfium::span<const uint8_t> src_span, int pixels, int image_width, int image_height, @@ -105,18 +114,14 @@ virtual void EnableStdConversion(bool bEnabled); virtual bool IsNormal() const; - // Returns |this| as a CPDF_PatternCS* if |this| is a pattern. - virtual CPDF_PatternCS* AsPatternCS(); + // Returns `this` as a CPDF_PatternCS* if `this` is a pattern. virtual const CPDF_PatternCS* AsPatternCS() const; - // Use instead of GetRGB() for patterns. - virtual bool GetPatternRGB(const PatternValue& value, - float* R, - float* G, - float* B) const; + // Returns `this` as a CPDF_IndexedCS* if `this` is indexed. + virtual const CPDF_IndexedCS* AsIndexedCS() const; protected: - CPDF_ColorSpace(CPDF_Document* pDoc, int family); + explicit CPDF_ColorSpace(Family family); ~CPDF_ColorSpace() override; // Returns the number of components, or 0 on failure. @@ -128,13 +133,20 @@ // components count. void SetComponentsForStockCS(uint32_t nComponents); - UnownedPtr<CPDF_Document> const m_pDocument; - RetainPtr<const CPDF_Array> m_pArray; - const int m_Family; - uint32_t m_dwStdConversion = 0; + bool IsStdConversionEnabled() const { return m_dwStdConversion != 0; } + bool HasSameArray(const CPDF_Object* pObj) const { return m_pArray == pObj; } private: + friend class CPDF_CalGray_TranslateImageLine_Test; + friend class CPDF_CalRGB_TranslateImageLine_Test; + + static RetainPtr<CPDF_ColorSpace> AllocateColorSpace( + ByteStringView bsFamilyName); + + const Family m_Family; + uint32_t m_dwStdConversion = 0; uint32_t m_nComponents = 0; + RetainPtr<const CPDF_Array> m_pArray; }; #endif // CORE_FPDFAPI_PAGE_CPDF_COLORSPACE_H_
diff --git a/core/fpdfapi/page/cpdf_colorspace_unittest.cpp b/core/fpdfapi/page/cpdf_colorspace_unittest.cpp new file mode 100644 index 0000000..d0196fe --- /dev/null +++ b/core/fpdfapi/page/cpdf_colorspace_unittest.cpp
@@ -0,0 +1,52 @@ +// Copyright 2021 The PDFium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "core/fpdfapi/page/cpdf_colorspace.h" + +#include <stdint.h> +#include <string.h> + +#include "core/fxcrt/retain_ptr.h" +#include "testing/gtest/include/gtest/gtest.h" + +TEST(CPDF_CalGray, TranslateImageLine) { + const uint8_t kSrc[12] = {255, 0, 0, 0, 255, 0, 0, 0, 255, 128, 128, 128}; + const uint8_t kExpect[12] = {255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + + RetainPtr<CPDF_ColorSpace> pCal = CPDF_ColorSpace::AllocateColorSpace("CalG"); + ASSERT_TRUE(pCal); + + uint8_t dst[12]; + memset(dst, 0xbd, sizeof(dst)); + pCal->TranslateImageLine(dst, kSrc, 4, 4, 1, true); + for (size_t i = 0; i < 12; ++i) + EXPECT_EQ(dst[i], kExpect[i]) << " at " << i; + + memset(dst, 0xbd, sizeof(dst)); + pCal->TranslateImageLine(dst, kSrc, 4, 4, 1, false); + for (size_t i = 0; i < 12; ++i) + EXPECT_EQ(dst[i], kExpect[i]) << " at " << i; +} + +TEST(CPDF_CalRGB, TranslateImageLine) { + const uint8_t kSrc[12] = {255, 0, 0, 0, 255, 0, 0, 0, 255, 128, 128, 128}; + const uint8_t kExpectMask[12] = {255, 58, 0, 0, 255, 0, + 70, 0, 255, 188, 188, 188}; + const uint8_t kExpectNomask[12] = {0, 0, 255, 0, 255, 0, + 255, 0, 0, 128, 128, 128}; + + RetainPtr<CPDF_ColorSpace> pCal = CPDF_ColorSpace::AllocateColorSpace("CalR"); + ASSERT_TRUE(pCal); + + uint8_t dst[12]; + memset(dst, 0xbd, sizeof(dst)); + pCal->TranslateImageLine(dst, kSrc, 4, 4, 1, true); + for (size_t i = 0; i < 12; ++i) + EXPECT_EQ(dst[i], kExpectMask[i]) << " at " << i; + + memset(dst, 0xbd, sizeof(dst)); + pCal->TranslateImageLine(dst, kSrc, 4, 4, 1, false); + for (size_t i = 0; i < 12; ++i) + EXPECT_EQ(dst[i], kExpectNomask[i]) << " at " << i; +}
diff --git a/core/fpdfapi/page/cpdf_colorstate.cpp b/core/fpdfapi/page/cpdf_colorstate.cpp index 50dbb71..a03fd43 100644 --- a/core/fpdfapi/page/cpdf_colorstate.cpp +++ b/core/fpdfapi/page/cpdf_colorstate.cpp
@@ -1,4 +1,4 @@ -// Copyright 2016 PDFium Authors. All rights reserved. +// Copyright 2016 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -6,17 +6,20 @@ #include "core/fpdfapi/page/cpdf_colorstate.h" +#include <utility> + #include "core/fpdfapi/page/cpdf_colorspace.h" #include "core/fpdfapi/page/cpdf_pattern.h" #include "core/fpdfapi/page/cpdf_tilingpattern.h" -#include "core/fxge/fx_dib.h" +#include "core/fxge/dib/fx_dib.h" +#include "third_party/base/check.h" -CPDF_ColorState::CPDF_ColorState() {} +CPDF_ColorState::CPDF_ColorState() = default; CPDF_ColorState::CPDF_ColorState(const CPDF_ColorState& that) : m_Ref(that.m_Ref) {} -CPDF_ColorState::~CPDF_ColorState() {} +CPDF_ColorState::~CPDF_ColorState() = default; void CPDF_ColorState::Emplace() { m_Ref.Emplace(); @@ -70,72 +73,74 @@ return pColor && !pColor->IsNull(); } -void CPDF_ColorState::SetFillColor(const RetainPtr<CPDF_ColorSpace>& pCS, - const std::vector<float>& values) { +void CPDF_ColorState::SetFillColor(RetainPtr<CPDF_ColorSpace> colorspace, + std::vector<float> values) { ColorData* pData = m_Ref.GetPrivateCopy(); - SetColor(pCS, values, &pData->m_FillColor, &pData->m_FillColorRef); + SetColor(std::move(colorspace), std::move(values), &pData->m_FillColor, + &pData->m_FillColorRef); } -void CPDF_ColorState::SetStrokeColor(const RetainPtr<CPDF_ColorSpace>& pCS, - const std::vector<float>& values) { +void CPDF_ColorState::SetStrokeColor(RetainPtr<CPDF_ColorSpace> colorspace, + std::vector<float> values) { ColorData* pData = m_Ref.GetPrivateCopy(); - SetColor(pCS, values, &pData->m_StrokeColor, &pData->m_StrokeColorRef); + SetColor(std::move(colorspace), std::move(values), &pData->m_StrokeColor, + &pData->m_StrokeColorRef); } -void CPDF_ColorState::SetFillPattern(const RetainPtr<CPDF_Pattern>& pPattern, - const std::vector<float>& values) { +void CPDF_ColorState::SetFillPattern(RetainPtr<CPDF_Pattern> pattern, + pdfium::span<float> values) { ColorData* pData = m_Ref.GetPrivateCopy(); - SetPattern(pPattern, values, &pData->m_FillColor, &pData->m_FillColorRef); + SetPattern(std::move(pattern), values, &pData->m_FillColor, + &pData->m_FillColorRef); } -void CPDF_ColorState::SetStrokePattern(const RetainPtr<CPDF_Pattern>& pPattern, - const std::vector<float>& values) { +void CPDF_ColorState::SetStrokePattern(RetainPtr<CPDF_Pattern> pattern, + pdfium::span<float> values) { ColorData* pData = m_Ref.GetPrivateCopy(); - SetPattern(pPattern, values, &pData->m_StrokeColor, &pData->m_StrokeColorRef); + SetPattern(std::move(pattern), values, &pData->m_StrokeColor, + &pData->m_StrokeColorRef); } -void CPDF_ColorState::SetColor(const RetainPtr<CPDF_ColorSpace>& pCS, - const std::vector<float>& values, +void CPDF_ColorState::SetColor(RetainPtr<CPDF_ColorSpace> colorspace, + std::vector<float> values, CPDF_Color* color, FX_COLORREF* colorref) { - ASSERT(color); - ASSERT(colorref); + DCHECK(color); + DCHECK(colorref); - if (pCS) - color->SetColorSpace(pCS); - else if (color->IsNull()) - color->SetColorSpace(CPDF_ColorSpace::GetStockCS(PDFCS_DEVICEGRAY)); - + if (colorspace) { + color->SetColorSpace(std::move(colorspace)); + } else if (color->IsNull()) { + color->SetColorSpace( + CPDF_ColorSpace::GetStockCS(CPDF_ColorSpace::Family::kDeviceGray)); + } if (color->CountComponents() > values.size()) return; if (!color->IsPattern()) - color->SetValueForNonPattern(values); + color->SetValueForNonPattern(std::move(values)); int R; int G; int B; *colorref = color->GetRGB(&R, &G, &B) ? FXSYS_BGR(B, G, R) : 0xFFFFFFFF; } -void CPDF_ColorState::SetPattern(const RetainPtr<CPDF_Pattern>& pPattern, - const std::vector<float>& values, +void CPDF_ColorState::SetPattern(RetainPtr<CPDF_Pattern> pattern, + pdfium::span<float> values, CPDF_Color* color, FX_COLORREF* colorref) { - ASSERT(color); - ASSERT(colorref); - - color->SetValueForPattern(pPattern, values); + DCHECK(color); + DCHECK(colorref); + color->SetValueForPattern(pattern, values); int R; int G; int B; - bool ret = color->GetRGB(&R, &G, &B); - if (CPDF_TilingPattern* pTilingPattern = pPattern->AsTilingPattern()) { - if (!ret && pTilingPattern->colored()) { - *colorref = 0x00BFBFBF; - return; - } + if (color->GetRGB(&R, &G, &B)) { + *colorref = FXSYS_BGR(B, G, R); + return; } - *colorref = ret ? FXSYS_BGR(B, G, R) : 0xFFFFFFFF; + CPDF_TilingPattern* tiling = pattern->AsTilingPattern(); + *colorref = tiling && tiling->colored() ? 0x00BFBFBF : 0xFFFFFFFF; } CPDF_ColorState::ColorData::ColorData() = default; @@ -151,8 +156,10 @@ void CPDF_ColorState::ColorData::SetDefault() { m_FillColorRef = 0; m_StrokeColorRef = 0; - m_FillColor.SetColorSpace(CPDF_ColorSpace::GetStockCS(PDFCS_DEVICEGRAY)); - m_StrokeColor.SetColorSpace(CPDF_ColorSpace::GetStockCS(PDFCS_DEVICEGRAY)); + m_FillColor.SetColorSpace( + CPDF_ColorSpace::GetStockCS(CPDF_ColorSpace::Family::kDeviceGray)); + m_StrokeColor.SetColorSpace( + CPDF_ColorSpace::GetStockCS(CPDF_ColorSpace::Family::kDeviceGray)); } RetainPtr<CPDF_ColorState::ColorData> CPDF_ColorState::ColorData::Clone()
diff --git a/core/fpdfapi/page/cpdf_colorstate.h b/core/fpdfapi/page/cpdf_colorstate.h index f0f6ebd..ec2de6b 100644 --- a/core/fpdfapi/page/cpdf_colorstate.h +++ b/core/fpdfapi/page/cpdf_colorstate.h
@@ -1,4 +1,4 @@ -// Copyright 2016 PDFium Authors. All rights reserved. +// Copyright 2016 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -10,12 +10,11 @@ #include <vector> #include "core/fpdfapi/page/cpdf_color.h" -#include "core/fxcrt/fx_system.h" #include "core/fxcrt/retain_ptr.h" #include "core/fxcrt/shared_copy_on_write.h" -#include "core/fxge/fx_dib.h" +#include "core/fxge/dib/fx_dib.h" +#include "third_party/base/span.h" -class CPDF_Color; class CPDF_ColorSpace; class CPDF_Pattern; @@ -42,22 +41,21 @@ CPDF_Color* GetMutableStrokeColor(); bool HasStrokeColor() const; - void SetFillColor(const RetainPtr<CPDF_ColorSpace>& pCS, - const std::vector<float>& values); - void SetStrokeColor(const RetainPtr<CPDF_ColorSpace>& pCS, - const std::vector<float>& values); - void SetFillPattern(const RetainPtr<CPDF_Pattern>& pattern, - const std::vector<float>& values); - void SetStrokePattern(const RetainPtr<CPDF_Pattern>& pattern, - const std::vector<float>& values); + void SetFillColor(RetainPtr<CPDF_ColorSpace> colorspace, + std::vector<float> values); + void SetStrokeColor(RetainPtr<CPDF_ColorSpace> colorspace, + std::vector<float> values); + void SetFillPattern(RetainPtr<CPDF_Pattern> pattern, + pdfium::span<float> values); + void SetStrokePattern(RetainPtr<CPDF_Pattern> pattern, + pdfium::span<float> values); bool HasRef() const { return !!m_Ref; } private: class ColorData final : public Retainable { public: - template <typename T, typename... Args> - friend RetainPtr<T> pdfium::MakeRetain(Args&&... args); + CONSTRUCT_VIA_MAKE_RETAIN; RetainPtr<ColorData> Clone() const; @@ -74,12 +72,12 @@ ~ColorData() override; }; - void SetColor(const RetainPtr<CPDF_ColorSpace>& pCS, - const std::vector<float>& values, + void SetColor(RetainPtr<CPDF_ColorSpace> colorspace, + std::vector<float> values, CPDF_Color* color, FX_COLORREF* colorref); - void SetPattern(const RetainPtr<CPDF_Pattern>& pPattern, - const std::vector<float>& values, + void SetPattern(RetainPtr<CPDF_Pattern> pattern, + pdfium::span<float> values, CPDF_Color* color, FX_COLORREF* colorref);
diff --git a/core/fpdfapi/page/cpdf_contentmarkitem.cpp b/core/fpdfapi/page/cpdf_contentmarkitem.cpp index a361e5b..6b5cd62 100644 --- a/core/fpdfapi/page/cpdf_contentmarkitem.cpp +++ b/core/fpdfapi/page/cpdf_contentmarkitem.cpp
@@ -1,4 +1,4 @@ -// Copyright 2016 PDFium Authors. All rights reserved. +// Copyright 2016 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -13,28 +13,23 @@ CPDF_ContentMarkItem::CPDF_ContentMarkItem(ByteString name) : m_MarkName(std::move(name)) {} -CPDF_ContentMarkItem::~CPDF_ContentMarkItem() {} +CPDF_ContentMarkItem::~CPDF_ContentMarkItem() = default; -const CPDF_Dictionary* CPDF_ContentMarkItem::GetParam() const { +RetainPtr<const CPDF_Dictionary> CPDF_ContentMarkItem::GetParam() const { switch (m_ParamType) { case kPropertiesDict: return m_pPropertiesHolder->GetDictFor(m_PropertyName); case kDirectDict: - return m_pDirectDict.Get(); + return m_pDirectDict; case kNone: default: return nullptr; } } -CPDF_Dictionary* CPDF_ContentMarkItem::GetParam() { - return const_cast<CPDF_Dictionary*>( - static_cast<const CPDF_ContentMarkItem*>(this)->GetParam()); -} - -bool CPDF_ContentMarkItem::HasMCID() const { - const CPDF_Dictionary* pDict = GetParam(); - return pDict && pDict->KeyExist("MCID"); +RetainPtr<CPDF_Dictionary> CPDF_ContentMarkItem::GetParam() { + return pdfium::WrapRetain( + const_cast<CPDF_Dictionary*>(std::as_const(*this).GetParam().Get())); } void CPDF_ContentMarkItem::SetDirectDict(RetainPtr<CPDF_Dictionary> pDict) { @@ -43,9 +38,9 @@ } void CPDF_ContentMarkItem::SetPropertiesHolder( - CPDF_Dictionary* pHolder, + RetainPtr<CPDF_Dictionary> pHolder, const ByteString& property_name) { m_ParamType = kPropertiesDict; - m_pPropertiesHolder.Reset(pHolder); + m_pPropertiesHolder = std::move(pHolder); m_PropertyName = property_name; }
diff --git a/core/fpdfapi/page/cpdf_contentmarkitem.h b/core/fpdfapi/page/cpdf_contentmarkitem.h index 15a34e9..f418aab 100644 --- a/core/fpdfapi/page/cpdf_contentmarkitem.h +++ b/core/fpdfapi/page/cpdf_contentmarkitem.h
@@ -1,4 +1,4 @@ -// Copyright 2016 PDFium Authors. All rights reserved. +// Copyright 2016 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -7,10 +7,7 @@ #ifndef CORE_FPDFAPI_PAGE_CPDF_CONTENTMARKITEM_H_ #define CORE_FPDFAPI_PAGE_CPDF_CONTENTMARKITEM_H_ -#include <memory> - -#include "core/fxcrt/fx_string.h" -#include "core/fxcrt/fx_system.h" +#include "core/fxcrt/bytestring.h" #include "core/fxcrt/retain_ptr.h" class CPDF_Dictionary; @@ -24,13 +21,12 @@ const ByteString& GetName() const { return m_MarkName; } ParamType GetParamType() const { return m_ParamType; } - const CPDF_Dictionary* GetParam() const; - CPDF_Dictionary* GetParam(); + RetainPtr<const CPDF_Dictionary> GetParam() const; + RetainPtr<CPDF_Dictionary> GetParam(); const ByteString& GetPropertyName() const { return m_PropertyName; } - bool HasMCID() const; void SetDirectDict(RetainPtr<CPDF_Dictionary> pDict); - void SetPropertiesHolder(CPDF_Dictionary* pHolder, + void SetPropertiesHolder(RetainPtr<CPDF_Dictionary> pHolder, const ByteString& property_name); private:
diff --git a/core/fpdfapi/page/cpdf_contentmarks.cpp b/core/fpdfapi/page/cpdf_contentmarks.cpp index 0b95ac5..4cb439e 100644 --- a/core/fpdfapi/page/cpdf_contentmarks.cpp +++ b/core/fpdfapi/page/cpdf_contentmarks.cpp
@@ -1,4 +1,4 @@ -// Copyright 2016 PDFium Authors. All rights reserved. +// Copyright 2016 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -10,14 +10,14 @@ #include <utility> #include "core/fpdfapi/parser/cpdf_dictionary.h" -#include "third_party/base/ptr_util.h" +#include "third_party/base/check_op.h" -CPDF_ContentMarks::CPDF_ContentMarks() {} +CPDF_ContentMarks::CPDF_ContentMarks() = default; -CPDF_ContentMarks::~CPDF_ContentMarks() {} +CPDF_ContentMarks::~CPDF_ContentMarks() = default; std::unique_ptr<CPDF_ContentMarks> CPDF_ContentMarks::Clone() { - auto result = pdfium::MakeUnique<CPDF_ContentMarks>(); + auto result = std::make_unique<CPDF_ContentMarks>(); if (m_pMarkData) result->m_pMarkData = pdfium::MakeRetain<MarkData>(*m_pMarkData); return result; @@ -32,12 +32,10 @@ } CPDF_ContentMarkItem* CPDF_ContentMarks::GetItem(size_t index) { - return const_cast<CPDF_ContentMarkItem*>( - static_cast<const CPDF_ContentMarks*>(this)->GetItem(index)); + return m_pMarkData->GetItem(index); } const CPDF_ContentMarkItem* CPDF_ContentMarks::GetItem(size_t index) const { - ASSERT(index < CountItems()); return m_pMarkData->GetItem(index); } @@ -50,18 +48,20 @@ m_pMarkData->AddMark(std::move(name)); } -void CPDF_ContentMarks::AddMarkWithDirectDict(ByteString name, - CPDF_Dictionary* pDict) { +void CPDF_ContentMarks::AddMarkWithDirectDict( + ByteString name, + RetainPtr<CPDF_Dictionary> pDict) { EnsureMarkDataExists(); - m_pMarkData->AddMarkWithDirectDict(std::move(name), pDict); + m_pMarkData->AddMarkWithDirectDict(std::move(name), std::move(pDict)); } void CPDF_ContentMarks::AddMarkWithPropertiesHolder( const ByteString& name, - CPDF_Dictionary* pDict, + RetainPtr<CPDF_Dictionary> pDict, const ByteString& property_name) { EnsureMarkDataExists(); - m_pMarkData->AddMarkWithPropertiesHolder(name, pDict, property_name); + m_pMarkData->AddMarkWithPropertiesHolder(name, std::move(pDict), + property_name); } bool CPDF_ContentMarks::RemoveMark(CPDF_ContentMarkItem* pMarkItem) { @@ -73,15 +73,6 @@ m_pMarkData = pdfium::MakeRetain<MarkData>(); } -void CPDF_ContentMarks::DeleteLastMark() { - if (!m_pMarkData) - return; - - m_pMarkData->DeleteLastMark(); - if (CountItems() == 0) - m_pMarkData.Reset(); -} - size_t CPDF_ContentMarks::FindFirstDifference( const CPDF_ContentMarks* other) const { if (m_pMarkData == other->m_pMarkData) @@ -96,12 +87,12 @@ return min_len; } -CPDF_ContentMarks::MarkData::MarkData() {} +CPDF_ContentMarks::MarkData::MarkData() = default; CPDF_ContentMarks::MarkData::MarkData(const MarkData& src) : m_Marks(src.m_Marks) {} -CPDF_ContentMarks::MarkData::~MarkData() {} +CPDF_ContentMarks::MarkData::~MarkData() = default; size_t CPDF_ContentMarks::MarkData::CountItems() const { return m_Marks.size(); @@ -109,7 +100,7 @@ bool CPDF_ContentMarks::MarkData::ContainsItem( const CPDF_ContentMarkItem* pItem) const { - for (const auto pMark : m_Marks) { + for (const auto& pMark : m_Marks) { if (pMark == pItem) return true; } @@ -117,17 +108,19 @@ } CPDF_ContentMarkItem* CPDF_ContentMarks::MarkData::GetItem(size_t index) { + CHECK_LT(index, m_Marks.size()); return m_Marks[index].Get(); } const CPDF_ContentMarkItem* CPDF_ContentMarks::MarkData::GetItem( size_t index) const { + CHECK_LT(index, m_Marks.size()); return m_Marks[index].Get(); } int CPDF_ContentMarks::MarkData::GetMarkedContentID() const { - for (const auto pMark : m_Marks) { - const CPDF_Dictionary* pDict = pMark->GetParam(); + for (const auto& pMark : m_Marks) { + RetainPtr<const CPDF_Dictionary> pDict = pMark->GetParam(); if (pDict && pDict->KeyExist("MCID")) return pDict->GetIntegerFor("MCID"); } @@ -141,7 +134,7 @@ void CPDF_ContentMarks::MarkData::AddMarkWithDirectDict( ByteString name, - CPDF_Dictionary* pDict) { + RetainPtr<CPDF_Dictionary> pDict) { auto pItem = pdfium::MakeRetain<CPDF_ContentMarkItem>(std::move(name)); pItem->SetDirectDict(ToDictionary(pDict->Clone())); m_Marks.push_back(pItem); @@ -149,11 +142,11 @@ void CPDF_ContentMarks::MarkData::AddMarkWithPropertiesHolder( const ByteString& name, - CPDF_Dictionary* pDict, + RetainPtr<CPDF_Dictionary> pDict, const ByteString& property_name) { auto pItem = pdfium::MakeRetain<CPDF_ContentMarkItem>(name); - pItem->SetPropertiesHolder(pDict, property_name); - m_Marks.push_back(pItem); + pItem->SetPropertiesHolder(std::move(pDict), property_name); + m_Marks.push_back(std::move(pItem)); } bool CPDF_ContentMarks::MarkData::RemoveMark(CPDF_ContentMarkItem* pMarkItem) { @@ -165,8 +158,3 @@ } return false; } - -void CPDF_ContentMarks::MarkData::DeleteLastMark() { - if (!m_Marks.empty()) - m_Marks.pop_back(); -}
diff --git a/core/fpdfapi/page/cpdf_contentmarks.h b/core/fpdfapi/page/cpdf_contentmarks.h index 7bb25ec..95eaeea 100644 --- a/core/fpdfapi/page/cpdf_contentmarks.h +++ b/core/fpdfapi/page/cpdf_contentmarks.h
@@ -1,4 +1,4 @@ -// Copyright 2016 PDFium Authors. All rights reserved. +// Copyright 2016 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -7,11 +7,12 @@ #ifndef CORE_FPDFAPI_PAGE_CPDF_CONTENTMARKS_H_ #define CORE_FPDFAPI_PAGE_CPDF_CONTENTMARKS_H_ +#include <stddef.h> + #include <memory> #include <vector> #include "core/fpdfapi/page/cpdf_contentmarkitem.h" -#include "core/fxcrt/fx_system.h" #include "core/fxcrt/retain_ptr.h" class CPDF_Dictionary; @@ -31,12 +32,11 @@ const CPDF_ContentMarkItem* GetItem(size_t index) const; void AddMark(ByteString name); - void AddMarkWithDirectDict(ByteString name, CPDF_Dictionary* pDict); + void AddMarkWithDirectDict(ByteString name, RetainPtr<CPDF_Dictionary> pDict); void AddMarkWithPropertiesHolder(const ByteString& name, - CPDF_Dictionary* pDict, + RetainPtr<CPDF_Dictionary> pDict, const ByteString& property_name); bool RemoveMark(CPDF_ContentMarkItem* pMarkItem); - void DeleteLastMark(); size_t FindFirstDifference(const CPDF_ContentMarks* other) const; private: @@ -53,12 +53,12 @@ int GetMarkedContentID() const; void AddMark(ByteString name); - void AddMarkWithDirectDict(ByteString name, CPDF_Dictionary* pDict); + void AddMarkWithDirectDict(ByteString name, + RetainPtr<CPDF_Dictionary> pDict); void AddMarkWithPropertiesHolder(const ByteString& name, - CPDF_Dictionary* pDict, + RetainPtr<CPDF_Dictionary> pDict, const ByteString& property_name); bool RemoveMark(CPDF_ContentMarkItem* pMarkItem); - void DeleteLastMark(); private: std::vector<RetainPtr<CPDF_ContentMarkItem>> m_Marks;
diff --git a/core/fpdfapi/page/cpdf_contentparser.cpp b/core/fpdfapi/page/cpdf_contentparser.cpp index 5b3efe1..5ef9d80 100644 --- a/core/fpdfapi/page/cpdf_contentparser.cpp +++ b/core/fpdfapi/page/cpdf_contentparser.cpp
@@ -1,4 +1,4 @@ -// Copyright 2016 PDFium Authors. All rights reserved. +// Copyright 2016 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -6,10 +6,11 @@ #include "core/fpdfapi/page/cpdf_contentparser.h" +#include <utility> + #include "constants/page_object.h" #include "core/fpdfapi/font/cpdf_type3char.h" #include "core/fpdfapi/page/cpdf_allstates.h" -#include "core/fpdfapi/page/cpdf_form.h" #include "core/fpdfapi/page/cpdf_page.h" #include "core/fpdfapi/page/cpdf_pageobject.h" #include "core/fpdfapi/page/cpdf_path.h" @@ -17,53 +18,61 @@ #include "core/fpdfapi/parser/cpdf_dictionary.h" #include "core/fpdfapi/parser/cpdf_stream.h" #include "core/fpdfapi/parser/cpdf_stream_acc.h" +#include "core/fxcrt/fixed_try_alloc_zeroed_data_vector.h" #include "core/fxcrt/fx_safe_types.h" #include "core/fxcrt/pauseindicator_iface.h" -#include "core/fxge/render_defines.h" -#include "third_party/base/ptr_util.h" +#include "core/fxcrt/span_util.h" +#include "core/fxcrt/stl_util.h" +#include "core/fxge/cfx_fillrenderoptions.h" +#include "third_party/base/check.h" +#include "third_party/base/check_op.h" CPDF_ContentParser::CPDF_ContentParser(CPDF_Page* pPage) - : m_CurrentStage(Stage::kGetContent), m_pObjectHolder(pPage) { - ASSERT(pPage); + : m_CurrentStage(Stage::kGetContent), m_pPageObjectHolder(pPage) { + DCHECK(pPage); if (!pPage->GetDocument()) { m_CurrentStage = Stage::kComplete; return; } - CPDF_Object* pContent = - pPage->GetDict()->GetDirectObjectFor(pdfium::page_object::kContents); + RetainPtr<CPDF_Object> pContent = + pPage->GetMutableDict()->GetMutableDirectObjectFor( + pdfium::page_object::kContents); if (!pContent) { HandlePageContentFailure(); return; } - CPDF_Stream* pStream = pContent->AsStream(); + const CPDF_Stream* pStream = pContent->AsStream(); if (pStream) { HandlePageContentStream(pStream); return; } - CPDF_Array* pArray = pContent->AsArray(); + const CPDF_Array* pArray = pContent->AsArray(); if (pArray && HandlePageContentArray(pArray)) return; HandlePageContentFailure(); } -CPDF_ContentParser::CPDF_ContentParser(CPDF_Form* pForm, +CPDF_ContentParser::CPDF_ContentParser(RetainPtr<const CPDF_Stream> pStream, + CPDF_PageObjectHolder* pPageObjectHolder, const CPDF_AllStates* pGraphicStates, const CFX_Matrix* pParentMatrix, CPDF_Type3Char* pType3Char, std::set<const uint8_t*>* pParsedSet) : m_CurrentStage(Stage::kParse), - m_pObjectHolder(pForm), + m_pPageObjectHolder(pPageObjectHolder), m_pType3Char(pType3Char) { - ASSERT(pForm); - CFX_Matrix form_matrix = pForm->GetDict()->GetMatrixFor("Matrix"); + DCHECK(m_pPageObjectHolder); + CFX_Matrix form_matrix = + m_pPageObjectHolder->GetDict()->GetMatrixFor("Matrix"); if (pGraphicStates) form_matrix.Concat(pGraphicStates->m_CTM); - CPDF_Array* pBBox = pForm->GetDict()->GetArrayFor("BBox"); + RetainPtr<const CPDF_Array> pBBox = + m_pPageObjectHolder->GetDict()->GetArrayFor("BBox"); CFX_FloatRect form_bbox; CPDF_Path ClipPath; if (pBBox) { @@ -79,31 +88,33 @@ form_bbox = pParentMatrix->TransformRect(form_bbox); } - CPDF_Dictionary* pResources = pForm->GetDict()->GetDictFor("Resources"); - m_pParser = pdfium::MakeUnique<CPDF_StreamContentParser>( - pForm->GetDocument(), pForm->m_pPageResources.Get(), - pForm->m_pResources.Get(), pParentMatrix, pForm, pResources, form_bbox, - pGraphicStates, pParsedSet); + RetainPtr<CPDF_Dictionary> pResources = + m_pPageObjectHolder->GetMutableDict()->GetMutableDictFor("Resources"); + m_pParser = std::make_unique<CPDF_StreamContentParser>( + m_pPageObjectHolder->GetDocument(), + m_pPageObjectHolder->GetMutablePageResources(), + m_pPageObjectHolder->GetMutableResources(), pParentMatrix, + m_pPageObjectHolder, std::move(pResources), form_bbox, pGraphicStates, + pParsedSet); m_pParser->GetCurStates()->m_CTM = form_matrix; m_pParser->GetCurStates()->m_ParentMatrix = form_matrix; if (ClipPath.HasRef()) { - m_pParser->GetCurStates()->m_ClipPath.AppendPath(ClipPath, FXFILL_WINDING, - true); + m_pParser->GetCurStates()->m_ClipPath.AppendPathWithAutoMerge( + ClipPath, CFX_FillRenderOptions::FillType::kWinding); } - if (pForm->GetTransparency().IsGroup()) { + if (m_pPageObjectHolder->GetTransparency().IsGroup()) { CPDF_GeneralState* pState = &m_pParser->GetCurStates()->m_GeneralState; pState->SetBlendType(BlendMode::kNormal); pState->SetStrokeAlpha(1.0f); pState->SetFillAlpha(1.0f); pState->SetSoftMask(nullptr); } - m_pSingleStream = pdfium::MakeRetain<CPDF_StreamAcc>(pForm->GetStream()); + m_pSingleStream = pdfium::MakeRetain<CPDF_StreamAcc>(std::move(pStream)); m_pSingleStream->LoadAllDataFiltered(); - m_pData.Reset(m_pSingleStream->GetData()); - m_Size = m_pSingleStream->GetSize(); + m_Data = m_pSingleStream->GetSpan(); } -CPDF_ContentParser::~CPDF_ContentParser() {} +CPDF_ContentParser::~CPDF_ContentParser() = default; // Returning |true| means that there is more content to be processed and // Continue() should be called again. Returning |false| means that we've @@ -127,19 +138,20 @@ if (m_CurrentStage == Stage::kCheckClip) m_CurrentStage = CheckClip(); - ASSERT(m_CurrentStage == Stage::kComplete); + DCHECK_EQ(m_CurrentStage, Stage::kComplete); return false; } CPDF_ContentParser::Stage CPDF_ContentParser::GetContent() { - ASSERT(m_CurrentStage == Stage::kGetContent); - ASSERT(m_pObjectHolder->IsPage()); - CPDF_Array* pContent = - m_pObjectHolder->GetDict()->GetArrayFor(pdfium::page_object::kContents); - CPDF_Stream* pStreamObj = ToStream( + DCHECK_EQ(m_CurrentStage, Stage::kGetContent); + DCHECK(m_pPageObjectHolder->IsPage()); + RetainPtr<const CPDF_Array> pContent = + m_pPageObjectHolder->GetDict()->GetArrayFor( + pdfium::page_object::kContents); + RetainPtr<const CPDF_Stream> pStreamObj = ToStream( pContent ? pContent->GetDirectObjectAt(m_CurrentOffset) : nullptr); m_StreamArray[m_CurrentOffset] = - pdfium::MakeRetain<CPDF_StreamAcc>(pStreamObj); + pdfium::MakeRetain<CPDF_StreamAcc>(std::move(pStreamObj)); m_StreamArray[m_CurrentOffset]->LoadAllDataFiltered(); m_CurrentOffset++; @@ -151,54 +163,56 @@ m_CurrentOffset = 0; if (m_StreamArray.empty()) { - m_pData.Reset(m_pSingleStream->GetData()); - m_Size = m_pSingleStream->GetSize(); + m_Data = m_pSingleStream->GetSpan(); return Stage::kParse; } - FX_SAFE_UINT32 safeSize = 0; + FX_SAFE_UINT32 safe_size = 0; for (const auto& stream : m_StreamArray) { - m_StreamSegmentOffsets.push_back(safeSize.ValueOrDie()); - - safeSize += stream->GetSize(); - safeSize += 1; - if (!safeSize.IsValid()) + m_StreamSegmentOffsets.push_back(safe_size.ValueOrDie()); + safe_size += stream->GetSize(); + safe_size += 1; + if (!safe_size.IsValid()) return Stage::kComplete; } - m_Size = safeSize.ValueOrDie(); - m_pData.Reset( - std::unique_ptr<uint8_t, FxFreeDeleter>(FX_Alloc(uint8_t, m_Size))); + const size_t buffer_size = safe_size.ValueOrDie(); + FixedTryAllocZeroedDataVector<uint8_t> buffer(buffer_size); + if (buffer.empty()) { + m_Data.emplace<pdfium::span<const uint8_t>>(); + return Stage::kComplete; + } - uint32_t pos = 0; + size_t pos = 0; + auto data_span = buffer.writable_span(); for (const auto& stream : m_StreamArray) { - memcpy(m_pData.Get() + pos, stream->GetData(), stream->GetSize()); + fxcrt::spancpy(data_span.subspan(pos), stream->GetSpan()); pos += stream->GetSize(); - m_pData.Get()[pos++] = ' '; + data_span[pos++] = ' '; } m_StreamArray.clear(); - + m_Data = std::move(buffer); return Stage::kParse; } CPDF_ContentParser::Stage CPDF_ContentParser::Parse() { if (!m_pParser) { - m_pParsedSet = pdfium::MakeUnique<std::set<const uint8_t*>>(); - m_pParser = pdfium::MakeUnique<CPDF_StreamContentParser>( - m_pObjectHolder->GetDocument(), m_pObjectHolder->m_pPageResources.Get(), - nullptr, nullptr, m_pObjectHolder.Get(), - m_pObjectHolder->m_pResources.Get(), m_pObjectHolder->GetBBox(), - nullptr, m_pParsedSet.get()); + m_ParsedSet.clear(); + m_pParser = std::make_unique<CPDF_StreamContentParser>( + m_pPageObjectHolder->GetDocument(), + m_pPageObjectHolder->GetMutablePageResources(), nullptr, nullptr, + m_pPageObjectHolder, m_pPageObjectHolder->GetMutableResources(), + m_pPageObjectHolder->GetBBox(), nullptr, &m_ParsedSet); m_pParser->GetCurStates()->m_ColorState.SetDefault(); } - if (m_CurrentOffset >= m_Size) + if (m_CurrentOffset >= GetData().size()) return Stage::kCheckClip; if (m_StreamSegmentOffsets.empty()) m_StreamSegmentOffsets.push_back(0); static constexpr uint32_t kParseStepLimit = 100; - m_CurrentOffset += m_pParser->Parse(m_pData.Get(), m_Size, m_CurrentOffset, + m_CurrentOffset += m_pParser->Parse(GetData(), m_CurrentOffset, kParseStepLimit, m_StreamSegmentOffsets); return Stage::kParse; } @@ -209,7 +223,7 @@ m_pParser->GetType3Data()); } - for (auto& pObj : *m_pObjectHolder) { + for (auto& pObj : *m_pPageObjectHolder) { if (!pObj->m_ClipPath.HasRef()) continue; if (pObj->m_ClipPath.GetPathCount() != 1) @@ -230,14 +244,15 @@ return Stage::kComplete; } -void CPDF_ContentParser::HandlePageContentStream(CPDF_Stream* pStream) { - m_pSingleStream = pdfium::MakeRetain<CPDF_StreamAcc>(pStream); +void CPDF_ContentParser::HandlePageContentStream(const CPDF_Stream* pStream) { + m_pSingleStream = + pdfium::MakeRetain<CPDF_StreamAcc>(pdfium::WrapRetain(pStream)); m_pSingleStream->LoadAllDataFiltered(); m_CurrentStage = Stage::kPrepareContent; } -bool CPDF_ContentParser::HandlePageContentArray(CPDF_Array* pArray) { - m_nStreams = pArray->size(); +bool CPDF_ContentParser::HandlePageContentArray(const CPDF_Array* pArray) { + m_nStreams = fxcrt::CollectionSize<uint32_t>(*pArray); if (m_nStreams == 0) return false; @@ -248,3 +263,9 @@ void CPDF_ContentParser::HandlePageContentFailure() { m_CurrentStage = Stage::kComplete; } + +pdfium::span<const uint8_t> CPDF_ContentParser::GetData() const { + if (is_owned()) + return absl::get<FixedTryAllocZeroedDataVector<uint8_t>>(m_Data).span(); + return absl::get<pdfium::span<const uint8_t>>(m_Data); +}
diff --git a/core/fpdfapi/page/cpdf_contentparser.h b/core/fpdfapi/page/cpdf_contentparser.h index 2f9a44b..090c624 100644 --- a/core/fpdfapi/page/cpdf_contentparser.h +++ b/core/fpdfapi/page/cpdf_contentparser.h
@@ -1,4 +1,4 @@ -// Copyright 2016 PDFium Authors. All rights reserved. +// Copyright 2016 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -7,18 +7,20 @@ #ifndef CORE_FPDFAPI_PAGE_CPDF_CONTENTPARSER_H_ #define CORE_FPDFAPI_PAGE_CPDF_CONTENTPARSER_H_ +#include <stdint.h> + #include <memory> #include <set> #include <vector> #include "core/fpdfapi/page/cpdf_streamcontentparser.h" -#include "core/fxcrt/fx_memory_wrappers.h" -#include "core/fxcrt/maybe_owned.h" +#include "core/fxcrt/fixed_try_alloc_zeroed_data_vector.h" +#include "core/fxcrt/retain_ptr.h" #include "core/fxcrt/unowned_ptr.h" +#include "third_party/abseil-cpp/absl/types/variant.h" class CPDF_AllStates; class CPDF_Array; -class CPDF_Form; class CPDF_Page; class CPDF_PageObjectHolder; class CPDF_Stream; @@ -29,7 +31,8 @@ class CPDF_ContentParser { public: explicit CPDF_ContentParser(CPDF_Page* pPage); - CPDF_ContentParser(CPDF_Form* pForm, + CPDF_ContentParser(RetainPtr<const CPDF_Stream> pStream, + CPDF_PageObjectHolder* pPageObjectHolder, const CPDF_AllStates* pGraphicStates, const CFX_Matrix* pParentMatrix, CPDF_Type3Char* pType3Char, @@ -56,26 +59,30 @@ Stage Parse(); Stage CheckClip(); - void HandlePageContentStream(CPDF_Stream* pStream); - bool HandlePageContentArray(CPDF_Array* pArray); + void HandlePageContentStream(const CPDF_Stream* pStream); + bool HandlePageContentArray(const CPDF_Array* pArray); void HandlePageContentFailure(); + bool is_owned() const { + return absl::holds_alternative<FixedTryAllocZeroedDataVector<uint8_t>>( + m_Data); + } + pdfium::span<const uint8_t> GetData() const; + Stage m_CurrentStage; - UnownedPtr<CPDF_PageObjectHolder> const m_pObjectHolder; + UnownedPtr<CPDF_PageObjectHolder> const m_pPageObjectHolder; UnownedPtr<CPDF_Type3Char> m_pType3Char; // Only used when parsing forms. RetainPtr<CPDF_StreamAcc> m_pSingleStream; std::vector<RetainPtr<CPDF_StreamAcc>> m_StreamArray; std::vector<uint32_t> m_StreamSegmentOffsets; - MaybeOwned<uint8_t, FxFreeDeleter> m_pData; + absl::variant<pdfium::span<const uint8_t>, + FixedTryAllocZeroedDataVector<uint8_t>> + m_Data; uint32_t m_nStreams = 0; - uint32_t m_Size = 0; uint32_t m_CurrentOffset = 0; + std::set<const uint8_t*> m_ParsedSet; // Only used when parsing pages. - // Only used when parsing pages. - std::unique_ptr<std::set<const uint8_t*>> m_pParsedSet; - - // |m_pParser| has a reference to |m_pParsedSet|, so must be below and thus - // destroyed first. + // Must not outlive |m_pParsedSet|. std::unique_ptr<CPDF_StreamContentParser> m_pParser; };
diff --git a/core/fpdfapi/page/cpdf_devicecs.cpp b/core/fpdfapi/page/cpdf_devicecs.cpp index e557516..5590c5b 100644 --- a/core/fpdfapi/page/cpdf_devicecs.cpp +++ b/core/fpdfapi/page/cpdf_devicecs.cpp
@@ -1,4 +1,4 @@ -// Copyright 2014 PDFium Authors. All rights reserved. +// Copyright 2014 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -6,8 +6,6 @@ #include "core/fpdfapi/page/cpdf_devicecs.h" -#include <limits.h> - #include <algorithm> #include "core/fpdfapi/parser/cpdf_array.h" @@ -17,8 +15,9 @@ #include "core/fpdfapi/parser/cpdf_string.h" #include "core/fxcodec/fx_codec.h" #include "core/fxge/dib/cfx_cmyk_to_srgb.h" -#include "third_party/base/logging.h" -#include "third_party/base/stl_util.h" +#include "third_party/base/check.h" +#include "third_party/base/cxx17_backports.h" +#include "third_party/base/notreached.h" namespace { @@ -28,9 +27,9 @@ } // namespace -CPDF_DeviceCS::CPDF_DeviceCS(int family) : CPDF_ColorSpace(nullptr, family) { - ASSERT(family == PDFCS_DEVICEGRAY || family == PDFCS_DEVICERGB || - family == PDFCS_DEVICECMYK); +CPDF_DeviceCS::CPDF_DeviceCS(Family family) : CPDF_ColorSpace(family) { + DCHECK(family == Family::kDeviceGray || family == Family::kDeviceRGB || + family == Family::kDeviceCMYK); SetComponentsForStockCS(ComponentsForFamily(GetFamily())); } @@ -41,27 +40,26 @@ std::set<const CPDF_Object*>* pVisited) { // Unlike other classes that inherit from CPDF_ColorSpace, CPDF_DeviceCS is // never loaded by CPDF_ColorSpace. - NOTREACHED(); - return 0; + NOTREACHED_NORETURN(); } -bool CPDF_DeviceCS::GetRGB(const float* pBuf, +bool CPDF_DeviceCS::GetRGB(pdfium::span<const float> pBuf, float* R, float* G, float* B) const { - switch (m_Family) { - case PDFCS_DEVICEGRAY: - *R = NormalizeChannel(*pBuf); + switch (GetFamily()) { + case Family::kDeviceGray: + *R = NormalizeChannel(pBuf[0]); *G = *R; *B = *R; return true; - case PDFCS_DEVICERGB: + case Family::kDeviceRGB: *R = NormalizeChannel(pBuf[0]); *G = NormalizeChannel(pBuf[1]); *B = NormalizeChannel(pBuf[2]); return true; - case PDFCS_DEVICECMYK: - if (m_dwStdConversion) { + case Family::kDeviceCMYK: + if (IsStdConversionEnabled()) { float k = pBuf[3]; *R = 1.0f - std::min(1.0f, pBuf[0] + k); *G = 1.0f - std::min(1.0f, pBuf[1] + k); @@ -73,57 +71,74 @@ } return true; default: - NOTREACHED(); - return false; + NOTREACHED_NORETURN(); } } -void CPDF_DeviceCS::TranslateImageLine(uint8_t* pDestBuf, - const uint8_t* pSrcBuf, +void CPDF_DeviceCS::TranslateImageLine(pdfium::span<uint8_t> dest_span, + pdfium::span<const uint8_t> src_span, int pixels, int image_width, int image_height, bool bTransMask) const { - switch (m_Family) { - case PDFCS_DEVICEGRAY: + uint8_t* pDestBuf = dest_span.data(); + const uint8_t* pSrcBuf = src_span.data(); + switch (GetFamily()) { + case Family::kDeviceGray: for (int i = 0; i < pixels; i++) { - *pDestBuf++ = pSrcBuf[i]; - *pDestBuf++ = pSrcBuf[i]; - *pDestBuf++ = pSrcBuf[i]; + // Compiler can not conclude that src/dest don't overlap, avoid + // duplicate loads. + const uint8_t pix = pSrcBuf[i]; + *pDestBuf++ = pix; + *pDestBuf++ = pix; + *pDestBuf++ = pix; } break; - case PDFCS_DEVICERGB: + case Family::kDeviceRGB: fxcodec::ReverseRGB(pDestBuf, pSrcBuf, pixels); break; - case PDFCS_DEVICECMYK: + case Family::kDeviceCMYK: if (bTransMask) { for (int i = 0; i < pixels; i++) { - int k = 255 - pSrcBuf[3]; - pDestBuf[0] = ((255 - pSrcBuf[0]) * k) / 255; - pDestBuf[1] = ((255 - pSrcBuf[1]) * k) / 255; - pDestBuf[2] = ((255 - pSrcBuf[2]) * k) / 255; + // Compiler can't conclude src/dest don't overlap, avoid interleaved + // loads and stores. + const uint8_t s0 = pSrcBuf[0]; + const uint8_t s1 = pSrcBuf[1]; + const uint8_t s2 = pSrcBuf[2]; + const int k = 255 - pSrcBuf[3]; + pDestBuf[0] = ((255 - s0) * k) / 255; + pDestBuf[1] = ((255 - s1) * k) / 255; + pDestBuf[2] = ((255 - s2) * k) / 255; pDestBuf += 3; pSrcBuf += 4; } } else { - for (int i = 0; i < pixels; i++) { - if (m_dwStdConversion) { - uint8_t k = pSrcBuf[3]; - pDestBuf[2] = 255 - std::min(255, pSrcBuf[0] + k); - pDestBuf[1] = 255 - std::min(255, pSrcBuf[1] + k); - pDestBuf[0] = 255 - std::min(255, pSrcBuf[2] + k); - } else { + if (IsStdConversionEnabled()) { + for (int i = 0; i < pixels; i++) { + // Compiler can't conclude src/dest don't overlap, avoid + // interleaved loads and stores. + const uint8_t s0 = pSrcBuf[0]; + const uint8_t s1 = pSrcBuf[1]; + const uint8_t s2 = pSrcBuf[2]; + const uint8_t k = pSrcBuf[3]; + pDestBuf[2] = 255 - std::min(255, s0 + k); + pDestBuf[1] = 255 - std::min(255, s1 + k); + pDestBuf[0] = 255 - std::min(255, s2 + k); + pSrcBuf += 4; + pDestBuf += 3; + } + } else { + for (int i = 0; i < pixels; i++) { std::tie(pDestBuf[2], pDestBuf[1], pDestBuf[0]) = AdobeCMYK_to_sRGB1(pSrcBuf[0], pSrcBuf[1], pSrcBuf[2], pSrcBuf[3]); + pSrcBuf += 4; + pDestBuf += 3; } - pSrcBuf += 4; - pDestBuf += 3; } } break; default: - NOTREACHED(); - break; + NOTREACHED_NORETURN(); } }
diff --git a/core/fpdfapi/page/cpdf_devicecs.h b/core/fpdfapi/page/cpdf_devicecs.h index c8e256c..8e8ca66 100644 --- a/core/fpdfapi/page/cpdf_devicecs.h +++ b/core/fpdfapi/page/cpdf_devicecs.h
@@ -1,4 +1,4 @@ -// Copyright 2017 PDFium Authors. All rights reserved. +// Copyright 2017 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -14,15 +14,16 @@ class CPDF_DeviceCS final : public CPDF_ColorSpace { public: - template <typename T, typename... Args> - friend RetainPtr<T> pdfium::MakeRetain(Args&&... args); - + CONSTRUCT_VIA_MAKE_RETAIN; ~CPDF_DeviceCS() override; // CPDF_ColorSpace: - bool GetRGB(const float* pBuf, float* R, float* G, float* B) const override; - void TranslateImageLine(uint8_t* pDestBuf, - const uint8_t* pSrcBuf, + bool GetRGB(pdfium::span<const float> pBuf, + float* R, + float* G, + float* B) const override; + void TranslateImageLine(pdfium::span<uint8_t> dest_span, + pdfium::span<const uint8_t> src_span, int pixels, int image_width, int image_height, @@ -32,7 +33,7 @@ std::set<const CPDF_Object*>* pVisited) override; private: - explicit CPDF_DeviceCS(int family); + explicit CPDF_DeviceCS(Family family); }; #endif // CORE_FPDFAPI_PAGE_CPDF_DEVICECS_H_
diff --git a/core/fpdfapi/page/cpdf_devicecs_unittest.cpp b/core/fpdfapi/page/cpdf_devicecs_unittest.cpp index fbf2558..4c3c348 100644 --- a/core/fpdfapi/page/cpdf_devicecs_unittest.cpp +++ b/core/fpdfapi/page/cpdf_devicecs_unittest.cpp
@@ -1,4 +1,4 @@ -// Copyright 2017 PDFium Authors. All rights reserved. +// Copyright 2017 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -13,7 +13,8 @@ float R; float G; float B; - auto device_gray = pdfium::MakeRetain<CPDF_DeviceCS>(PDFCS_DEVICEGRAY); + auto device_gray = + pdfium::MakeRetain<CPDF_DeviceCS>(CPDF_ColorSpace::Family::kDeviceGray); // Test normal values. For gray, only first value from buf should be used. float buf[3] = {0.43f, 0.11f, 0.34f}; @@ -56,7 +57,8 @@ float R; float G; float B; - auto device_rgb = pdfium::MakeRetain<CPDF_DeviceCS>(PDFCS_DEVICERGB); + auto device_rgb = + pdfium::MakeRetain<CPDF_DeviceCS>(CPDF_ColorSpace::Family::kDeviceRGB); // Test normal values float buf[3] = {0.13f, 1.0f, 0.652f}; @@ -85,7 +87,8 @@ float R; float G; float B; - auto device_cmyk = pdfium::MakeRetain<CPDF_DeviceCS>(PDFCS_DEVICECMYK); + auto device_cmyk = + pdfium::MakeRetain<CPDF_DeviceCS>(CPDF_ColorSpace::Family::kDeviceCMYK); // Test normal values float buf[4] = {0.6f, 0.5f, 0.3f, 0.9f};
diff --git a/core/fpdfapi/page/cpdf_dib.cpp b/core/fpdfapi/page/cpdf_dib.cpp index 6976a0d..29db5a4 100644 --- a/core/fpdfapi/page/cpdf_dib.cpp +++ b/core/fpdfapi/page/cpdf_dib.cpp
@@ -1,4 +1,4 @@ -// Copyright 2017 PDFium Authors. All rights reserved. +// Copyright 2017 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -6,6 +6,8 @@ #include "core/fpdfapi/page/cpdf_dib.h" +#include <stdint.h> + #include <algorithm> #include <memory> #include <utility> @@ -15,33 +17,41 @@ #include "core/fpdfapi/page/cpdf_docpagedata.h" #include "core/fpdfapi/page/cpdf_image.h" #include "core/fpdfapi/page/cpdf_imageobject.h" +#include "core/fpdfapi/page/cpdf_indexedcs.h" #include "core/fpdfapi/parser/cpdf_array.h" #include "core/fpdfapi/parser/cpdf_dictionary.h" #include "core/fpdfapi/parser/cpdf_document.h" +#include "core/fpdfapi/parser/cpdf_name.h" +#include "core/fpdfapi/parser/cpdf_number.h" #include "core/fpdfapi/parser/cpdf_stream.h" #include "core/fpdfapi/parser/cpdf_stream_acc.h" #include "core/fpdfapi/parser/fpdf_parser_decode.h" #include "core/fpdfapi/parser/fpdf_parser_utility.h" #include "core/fxcodec/basic/basicmodule.h" -#include "core/fxcodec/fx_codec.h" -#include "core/fxcodec/jbig2/jbig2module.h" +#include "core/fxcodec/jbig2/jbig2_decoder.h" #include "core/fxcodec/jpeg/jpegmodule.h" #include "core/fxcodec/jpx/cjpx_decoder.h" -#include "core/fxcodec/jpx/jpxmodule.h" #include "core/fxcodec/scanlinedecoder.h" -#include "core/fxcrt/cfx_fixedbufgrow.h" +#include "core/fxcrt/data_vector.h" #include "core/fxcrt/fx_safe_types.h" +#include "core/fxcrt/span_util.h" +#include "core/fxge/calculate_pitch.h" #include "core/fxge/dib/cfx_dibitmap.h" -#include "third_party/base/ptr_util.h" -#include "third_party/base/stl_util.h" +#include "third_party/base/check.h" +#include "third_party/base/check_op.h" +#include "third_party/base/cxx17_backports.h" +#include "third_party/base/notreached.h" namespace { -constexpr int kMaxImageDimension = 0x01FFFF; +bool IsValidDimension(int value) { + constexpr int kMaxImageDimension = 0x01FFFF; + return value > 0 && value <= kMaxImageDimension; +} unsigned int GetBits8(const uint8_t* pData, uint64_t bitpos, size_t nbits) { - ASSERT(nbits == 1 || nbits == 2 || nbits == 4 || nbits == 8 || nbits == 16); - ASSERT((bitpos & (nbits - 1)) == 0); + DCHECK(nbits == 1 || nbits == 2 || nbits == 4 || nbits == 8 || nbits == 16); + DCHECK_EQ((bitpos & (nbits - 1)), 0); unsigned int byte = pData[bitpos / 8]; if (nbits == 8) return byte; @@ -80,7 +90,7 @@ } int CalculateBitsPerPixel(uint32_t bpc, uint32_t comps) { - // TODO(thestig): Can |bpp| be 0 here? Add an ASSERT() or handle it? + // TODO(thestig): Can |bpp| be 0 here? Add an DCHECK() or handle it? uint32_t bpp = bpc * comps; if (bpp == 1) return 1; @@ -93,7 +103,7 @@ CPDF_ColorSpace* pCS) { if (!pCS) return CJPX_Decoder::kNoColorSpace; - if (pCS->GetFamily() == PDFCS_INDEXED) + if (pCS->GetFamily() == CPDF_ColorSpace::Family::kIndexed) return CJPX_Decoder::kIndexedColorSpace; return CJPX_Decoder::kNormalColorSpace; } @@ -101,179 +111,192 @@ enum class JpxDecodeAction { kFail, kDoNothing, + kUseGray, kUseRgb, kUseCmyk, + kConvertArgbToRgb, }; -JpxDecodeAction GetJpxDecodeAction(uint32_t jpx_components, - const CPDF_ColorSpace* pdf_colorspace) { - if (pdf_colorspace) { - // Make sure the JPX image and the PDF colorspace agree on the number of - // components. - if (jpx_components != pdf_colorspace->CountComponents()) +// Decides which JpxDecodeAction to use based on the colorspace information from +// the PDF and the JPX image. Called only when the PDF's image object contains a +// "/ColorSpace" entry. +JpxDecodeAction GetJpxDecodeActionFromColorSpaces( + const CJPX_Decoder::JpxImageInfo& jpx_info, + const CPDF_ColorSpace* pdf_colorspace) { + if (pdf_colorspace == + CPDF_ColorSpace::GetStockCS(CPDF_ColorSpace::Family::kDeviceGray)) { + if (jpx_info.colorspace != OPJ_CLRSPC_GRAY && + jpx_info.colorspace != OPJ_CLRSPC_UNSPECIFIED) { return JpxDecodeAction::kFail; - - if (pdf_colorspace == CPDF_ColorSpace::GetStockCS(PDFCS_DEVICERGB)) - return JpxDecodeAction::kUseRgb; - - return JpxDecodeAction::kDoNothing; + } + return JpxDecodeAction::kUseGray; } - // Cases where the PDF did not provide a colorspace. - // Choose how to decode based on the number of components in the JPX image. - switch (jpx_components) { - case 3: + if (pdf_colorspace == + CPDF_ColorSpace::GetStockCS(CPDF_ColorSpace::Family::kDeviceRGB)) { + if (jpx_info.colorspace != OPJ_CLRSPC_SRGB && + jpx_info.colorspace != OPJ_CLRSPC_UNSPECIFIED) { + return JpxDecodeAction::kFail; + } + + // The channel count of a JPX image can be different from the PDF color + // space's component count. + if (jpx_info.channels > 3) { + return JpxDecodeAction::kConvertArgbToRgb; + } + return JpxDecodeAction::kUseRgb; + } + + if (pdf_colorspace == + CPDF_ColorSpace::GetStockCS(CPDF_ColorSpace::Family::kDeviceCMYK)) { + if (jpx_info.colorspace != OPJ_CLRSPC_CMYK && + jpx_info.colorspace != OPJ_CLRSPC_UNSPECIFIED) { + return JpxDecodeAction::kFail; + } + return JpxDecodeAction::kUseCmyk; + } + + return JpxDecodeAction::kDoNothing; +} + +JpxDecodeAction GetJpxDecodeActionFromImageColorSpace( + const CJPX_Decoder::JpxImageInfo& jpx_info) { + switch (jpx_info.colorspace) { + case OPJ_CLRSPC_SYCC: + case OPJ_CLRSPC_EYCC: + case OPJ_CLRSPC_UNKNOWN: + case OPJ_CLRSPC_UNSPECIFIED: + return JpxDecodeAction::kDoNothing; + + case OPJ_CLRSPC_SRGB: + if (jpx_info.channels > 3) { + return JpxDecodeAction::kConvertArgbToRgb; + } + return JpxDecodeAction::kUseRgb; - case 4: + case OPJ_CLRSPC_GRAY: + return JpxDecodeAction::kUseGray; + + case OPJ_CLRSPC_CMYK: return JpxDecodeAction::kUseCmyk; default: - return JpxDecodeAction::kDoNothing; + NOTREACHED_NORETURN(); + } +} + +JpxDecodeAction GetJpxDecodeAction(const CJPX_Decoder::JpxImageInfo& jpx_info, + const CPDF_ColorSpace* pdf_colorspace) { + if (pdf_colorspace) { + return GetJpxDecodeActionFromColorSpaces(jpx_info, pdf_colorspace); + } + + // When PDF does not provide a color space, check the image color space. + return GetJpxDecodeActionFromImageColorSpace(jpx_info); +} + +int GetComponentCountFromOpjColorSpace(OPJ_COLOR_SPACE colorspace) { + switch (colorspace) { + case OPJ_CLRSPC_GRAY: + return 1; + + case OPJ_CLRSPC_SRGB: + case OPJ_CLRSPC_SYCC: + case OPJ_CLRSPC_EYCC: + return 3; + + case OPJ_CLRSPC_CMYK: + return 4; + + default: + return 0; } } } // namespace -CPDF_DIB::CPDF_DIB() = default; +CPDF_DIB::CPDF_DIB(CPDF_Document* pDoc, RetainPtr<const CPDF_Stream> pStream) + : m_pDocument(pDoc), m_pStream(std::move(pStream)) {} CPDF_DIB::~CPDF_DIB() = default; -bool CPDF_DIB::Load(CPDF_Document* pDoc, const CPDF_Stream* pStream) { - if (!pStream) +CPDF_DIB::JpxSMaskInlineData::JpxSMaskInlineData() = default; + +CPDF_DIB::JpxSMaskInlineData::~JpxSMaskInlineData() = default; + +bool CPDF_DIB::Load() { + if (!LoadInternal(nullptr, nullptr)) return false; - m_pDocument = pDoc; - m_pDict.Reset(pStream->GetDict()); - if (!m_pDict) + if (CreateDecoder(0) == LoadState::kFail) return false; - m_pStream.Reset(pStream); - m_Width = m_pDict->GetIntegerFor("Width"); - m_Height = m_pDict->GetIntegerFor("Height"); - if (m_Width <= 0 || m_Height <= 0 || m_Width > kMaxImageDimension || - m_Height > kMaxImageDimension) { - return false; - } - m_GroupFamily = 0; - m_bLoadMask = false; - if (!LoadColorInfo(nullptr, nullptr)) - return false; - - if (m_bDoBpcCheck && (m_bpc == 0 || m_nComponents == 0)) - return false; - - FX_SAFE_UINT32 src_size = - fxcodec::CalculatePitch8(m_bpc, m_nComponents, m_Width) * m_Height; - if (!src_size.IsValid()) - return false; - - m_pStreamAcc = pdfium::MakeRetain<CPDF_StreamAcc>(pStream); - m_pStreamAcc->LoadAllDataImageAcc(src_size.ValueOrDie()); - if (m_pStreamAcc->GetSize() == 0 || !m_pStreamAcc->GetData()) - return false; - - if (CreateDecoder() == LoadState::kFail) - return false; - - if (m_bImageMask) - SetMaskProperties(); - else - m_bpp = CalculateBitsPerPixel(m_bpc, m_nComponents); - - FX_SAFE_UINT32 pitch = fxcodec::CalculatePitch32(m_bpp, m_Width); - if (!pitch.IsValid()) - return false; - - m_pLineBuf.reset(FX_Alloc(uint8_t, pitch.ValueOrDie())); - LoadPalette(); - if (m_bColorKey) { - m_bpp = 32; - m_AlphaFlag = 2; - pitch = fxcodec::CalculatePitch32(m_bpp, m_Width); - if (!pitch.IsValid()) - return false; - - m_pMaskedLine.reset(FX_Alloc(uint8_t, pitch.ValueOrDie())); - } - m_Pitch = pitch.ValueOrDie(); - return true; + return ContinueInternal(); } bool CPDF_DIB::ContinueToLoadMask() { + if (m_pColorSpace && m_bStdCS) + m_pColorSpace->EnableStdConversion(true); + + return ContinueInternal(); +} + +bool CPDF_DIB::ContinueInternal() { if (m_bImageMask) { SetMaskProperties(); } else { if (!m_bpc || !m_nComponents) return false; - m_bpp = CalculateBitsPerPixel(m_bpc, m_nComponents); + m_Format = MakeRGBFormat(CalculateBitsPerPixel(m_bpc, m_nComponents)); } - FX_SAFE_UINT32 pitch = fxcodec::CalculatePitch32(m_bpp, m_Width); - if (!pitch.IsValid()) + absl::optional<uint32_t> pitch = + fxge::CalculatePitch32(GetBppFromFormat(m_Format), m_Width); + if (!pitch.has_value()) return false; - m_pLineBuf.reset(FX_Alloc(uint8_t, pitch.ValueOrDie())); - if (m_pColorSpace && m_bStdCS) { - m_pColorSpace->EnableStdConversion(true); - } + m_LineBuf = DataVector<uint8_t>(pitch.value()); LoadPalette(); if (m_bColorKey) { - m_bpp = 32; - m_AlphaFlag = 2; - pitch = fxcodec::CalculatePitch32(m_bpp, m_Width); - if (!pitch.IsValid()) + m_Format = FXDIB_Format::kArgb; + pitch = fxge::CalculatePitch32(GetBppFromFormat(m_Format), m_Width); + if (!pitch.has_value()) return false; - m_pMaskedLine.reset(FX_Alloc(uint8_t, pitch.ValueOrDie())); + m_MaskBuf = DataVector<uint8_t>(pitch.value()); } - m_Pitch = pitch.ValueOrDie(); + m_Pitch = pitch.value(); return true; } CPDF_DIB::LoadState CPDF_DIB::StartLoadDIBBase( - CPDF_Document* pDoc, - const CPDF_Stream* pStream, bool bHasMask, const CPDF_Dictionary* pFormResources, - CPDF_Dictionary* pPageResources, + const CPDF_Dictionary* pPageResources, bool bStdCS, - uint32_t GroupFamily, - bool bLoadMask) { - if (!pStream) - return LoadState::kFail; - - m_pDocument = pDoc; - m_pDict.Reset(pStream->GetDict()); - m_pStream.Reset(pStream); + CPDF_ColorSpace::Family GroupFamily, + bool bLoadMask, + const CFX_Size& max_size_required) { m_bStdCS = bStdCS; m_bHasMask = bHasMask; - m_Width = m_pDict->GetIntegerFor("Width"); - m_Height = m_pDict->GetIntegerFor("Height"); - if (m_Width <= 0 || m_Height <= 0 || m_Width > kMaxImageDimension || - m_Height > kMaxImageDimension) { - return LoadState::kFail; - } m_GroupFamily = GroupFamily; m_bLoadMask = bLoadMask; - if (!LoadColorInfo(m_pStream->IsInline() ? pFormResources : nullptr, - pPageResources)) { + + if (!m_pStream->IsInline()) + pFormResources = nullptr; + + if (!LoadInternal(pFormResources, pPageResources)) return LoadState::kFail; + + uint8_t resolution_levels_to_skip = 0; + if (max_size_required.width != 0 && max_size_required.height != 0) { + resolution_levels_to_skip = static_cast<uint8_t>( + std::log2(std::max(1, std::min(m_Width / max_size_required.width, + m_Height / max_size_required.height)))); } - if (m_bDoBpcCheck && (m_bpc == 0 || m_nComponents == 0)) - return LoadState::kFail; - FX_SAFE_UINT32 src_size = - fxcodec::CalculatePitch8(m_bpc, m_nComponents, m_Width) * m_Height; - if (!src_size.IsValid()) - return LoadState::kFail; - - m_pStreamAcc = pdfium::MakeRetain<CPDF_StreamAcc>(pStream); - m_pStreamAcc->LoadAllDataImageAcc(src_size.ValueOrDie()); - if (m_pStreamAcc->GetSize() == 0 || !m_pStreamAcc->GetData()) - return LoadState::kFail; - - LoadState iCreatedDecoder = CreateDecoder(); + LoadState iCreatedDecoder = CreateDecoder(resolution_levels_to_skip); if (iCreatedDecoder == LoadState::kFail) return LoadState::kFail; @@ -286,8 +309,8 @@ return LoadState::kContinue; } - ASSERT(iCreatedDecoder == LoadState::kSuccess); - ASSERT(iLoadedMask == LoadState::kSuccess); + DCHECK_EQ(iCreatedDecoder, LoadState::kSuccess); + DCHECK_EQ(iLoadedMask, LoadState::kSuccess); if (m_pColorSpace && m_bStdCS) m_pColorSpace->EnableStdConversion(false); return LoadState::kSuccess; @@ -308,47 +331,43 @@ return LoadState::kFail; FXCODEC_STATUS iDecodeStatus; - Jbig2Module* pJbig2Module = - fxcodec::ModuleMgr::GetInstance()->GetJbig2Module(); if (!m_pJbig2Context) { - m_pJbig2Context = pdfium::MakeUnique<Jbig2Context>(); + m_pJbig2Context = std::make_unique<Jbig2Context>(); if (m_pStreamAcc->GetImageParam()) { - const CPDF_Stream* pGlobals = + RetainPtr<const CPDF_Stream> pGlobals = m_pStreamAcc->GetImageParam()->GetStreamFor("JBIG2Globals"); if (pGlobals) { - m_pGlobalAcc = pdfium::MakeRetain<CPDF_StreamAcc>(pGlobals); + m_pGlobalAcc = pdfium::MakeRetain<CPDF_StreamAcc>(std::move(pGlobals)); m_pGlobalAcc->LoadAllDataFiltered(); } } - uint32_t nSrcObjNum = 0; + uint64_t nSrcKey = 0; pdfium::span<const uint8_t> pSrcSpan; if (m_pStreamAcc) { pSrcSpan = m_pStreamAcc->GetSpan(); - if (m_pStreamAcc->GetStream()) - nSrcObjNum = m_pStreamAcc->GetStream()->GetObjNum(); + nSrcKey = m_pStreamAcc->KeyForCache(); } - uint32_t nGlobalObjNum = 0; + uint64_t nGlobalKey = 0; pdfium::span<const uint8_t> pGlobalSpan; if (m_pGlobalAcc) { pGlobalSpan = m_pGlobalAcc->GetSpan(); - if (m_pGlobalAcc->GetStream()) - nGlobalObjNum = m_pGlobalAcc->GetStream()->GetObjNum(); + nGlobalKey = m_pGlobalAcc->KeyForCache(); } - iDecodeStatus = pJbig2Module->StartDecode( - m_pJbig2Context.get(), m_pDocument->CodecContext(), m_Width, m_Height, - pSrcSpan, nSrcObjNum, pGlobalSpan, nGlobalObjNum, + iDecodeStatus = Jbig2Decoder::StartDecode( + m_pJbig2Context.get(), m_pDocument->GetOrCreateCodecContext(), m_Width, + m_Height, pSrcSpan, nSrcKey, pGlobalSpan, nGlobalKey, m_pCachedBitmap->GetBuffer(), m_pCachedBitmap->GetPitch(), pPause); } else { - iDecodeStatus = pJbig2Module->ContinueDecode(m_pJbig2Context.get(), pPause); + iDecodeStatus = Jbig2Decoder::ContinueDecode(m_pJbig2Context.get(), pPause); } - if (iDecodeStatus < 0) { + if (iDecodeStatus == FXCODEC_STATUS::kError) { m_pJbig2Context.reset(); m_pCachedBitmap.Reset(); m_pGlobalAcc.Reset(); return LoadState::kFail; } - if (iDecodeStatus == FXCODEC_STATUS_DECODE_TOBECONTINUE) + if (iDecodeStatus == FXCODEC_STATUS::kDecodeToBeContinued) return LoadState::kContinue; LoadState iContinueStatus = LoadState::kSuccess; @@ -368,58 +387,51 @@ bool CPDF_DIB::LoadColorInfo(const CPDF_Dictionary* pFormResources, const CPDF_Dictionary* pPageResources) { + absl::optional<DecoderArray> decoder_array = GetDecoderArray(m_pDict); + if (!decoder_array.has_value()) + return false; + m_bpc_orig = m_pDict->GetIntegerFor("BitsPerComponent"); if (!IsMaybeValidBitsPerComponent(m_bpc_orig)) return false; - if (m_pDict->GetIntegerFor("ImageMask")) - m_bImageMask = true; + m_bImageMask = m_pDict->GetBooleanFor("ImageMask", /*bDefault=*/false); if (m_bImageMask || !m_pDict->KeyExist("ColorSpace")) { - if (!m_bImageMask) { - const CPDF_Object* pFilter = m_pDict->GetDirectObjectFor("Filter"); - if (pFilter) { - ByteString filter; - if (pFilter->IsName()) { - filter = pFilter->GetString(); - } else if (const CPDF_Array* pArray = pFilter->AsArray()) { - if (!ValidateDecoderPipeline(pArray)) - return false; - filter = pArray->GetStringAt(pArray->size() - 1); - } - - if (filter == "JPXDecode") { - m_bDoBpcCheck = false; - return true; - } + if (!m_bImageMask && !decoder_array.value().empty()) { + const ByteString& filter = decoder_array.value().back().first; + if (filter == "JPXDecode") { + m_bDoBpcCheck = false; + return true; } } m_bImageMask = true; m_bpc = m_nComponents = 1; - const CPDF_Array* pDecode = m_pDict->GetArrayFor("Decode"); + RetainPtr<const CPDF_Array> pDecode = m_pDict->GetArrayFor("Decode"); m_bDefaultDecode = !pDecode || !pDecode->GetIntegerAt(0); return true; } - const CPDF_Object* pCSObj = m_pDict->GetDirectObjectFor("ColorSpace"); + RetainPtr<const CPDF_Object> pCSObj = + m_pDict->GetDirectObjectFor("ColorSpace"); if (!pCSObj) return false; - auto* pDocPageData = CPDF_DocPageData::FromDocument(m_pDocument.Get()); + auto* pDocPageData = CPDF_DocPageData::FromDocument(m_pDocument); if (pFormResources) - m_pColorSpace = pDocPageData->GetColorSpace(pCSObj, pFormResources); + m_pColorSpace = pDocPageData->GetColorSpace(pCSObj.Get(), pFormResources); if (!m_pColorSpace) - m_pColorSpace = pDocPageData->GetColorSpace(pCSObj, pPageResources); + m_pColorSpace = pDocPageData->GetColorSpace(pCSObj.Get(), pPageResources); if (!m_pColorSpace) return false; // If the checks above failed to find a colorspace, and the next line to set // |m_nComponents| does not get reached, then a decoder can try to set - // |m_nComponents| based on the number of components in the image being + // |m_nComponents| based on the number of channels in the image being // decoded. m_nComponents = m_pColorSpace->CountComponents(); m_Family = m_pColorSpace->GetFamily(); - if (m_Family == PDFCS_ICCBASED && pCSObj->IsName()) { + if (m_Family == CPDF_ColorSpace::Family::kICCBased && pCSObj->IsName()) { ByteString cs = pCSObj->GetString(); if (cs == "DeviceGray") m_nComponents = 1; @@ -428,37 +440,44 @@ else if (cs == "DeviceCMYK") m_nComponents = 4; } - ValidateDictParam(); - return GetDecodeAndMaskArray(&m_bDefaultDecode, &m_bColorKey); + + ByteString filter; + if (!decoder_array.value().empty()) + filter = decoder_array.value().back().first; + + if (!ValidateDictParam(filter)) + return false; + + return GetDecodeAndMaskArray(); } -bool CPDF_DIB::GetDecodeAndMaskArray(bool* bDefaultDecode, bool* bColorKey) { +bool CPDF_DIB::GetDecodeAndMaskArray() { if (!m_pColorSpace) return false; m_CompData.resize(m_nComponents); int max_data = (1 << m_bpc) - 1; - const CPDF_Array* pDecode = m_pDict->GetArrayFor("Decode"); + RetainPtr<const CPDF_Array> pDecode = m_pDict->GetArrayFor("Decode"); if (pDecode) { for (uint32_t i = 0; i < m_nComponents; i++) { - m_CompData[i].m_DecodeMin = pDecode->GetNumberAt(i * 2); - float max = pDecode->GetNumberAt(i * 2 + 1); + m_CompData[i].m_DecodeMin = pDecode->GetFloatAt(i * 2); + float max = pDecode->GetFloatAt(i * 2 + 1); m_CompData[i].m_DecodeStep = (max - m_CompData[i].m_DecodeMin) / max_data; float def_value; float def_min; float def_max; m_pColorSpace->GetDefaultValue(i, &def_value, &def_min, &def_max); - if (m_Family == PDFCS_INDEXED) + if (m_Family == CPDF_ColorSpace::Family::kIndexed) def_max = max_data; if (def_min != m_CompData[i].m_DecodeMin || def_max != max) - *bDefaultDecode = false; + m_bDefaultDecode = false; } } else { for (uint32_t i = 0; i < m_nComponents; i++) { float def_value; m_pColorSpace->GetDefaultValue(i, &def_value, &m_CompData[i].m_DecodeMin, &m_CompData[i].m_DecodeStep); - if (m_Family == PDFCS_INDEXED) + if (m_Family == CPDF_ColorSpace::Family::kIndexed) m_CompData[i].m_DecodeStep = max_data; m_CompData[i].m_DecodeStep = (m_CompData[i].m_DecodeStep - m_CompData[i].m_DecodeMin) / max_data; @@ -467,7 +486,7 @@ if (m_pDict->KeyExist("SMask")) return true; - const CPDF_Object* pMask = m_pDict->GetDirectObjectFor("Mask"); + RetainPtr<const CPDF_Object> pMask = m_pDict->GetDirectObjectFor("Mask"); if (!pMask) return true; @@ -480,12 +499,12 @@ m_CompData[i].m_ColorKeyMax = std::min(max_num, max_data); } } - *bColorKey = true; + m_bColorKey = true; } return true; } -CPDF_DIB::LoadState CPDF_DIB::CreateDecoder() { +CPDF_DIB::LoadState CPDF_DIB::CreateDecoder(uint8_t resolution_levels_to_skip) { ByteString decoder = m_pStreamAcc->GetImageDecoder(); if (decoder.IsEmpty()) return LoadState::kSuccess; @@ -494,14 +513,15 @@ return LoadState::kFail; if (decoder == "JPXDecode") { - m_pCachedBitmap = LoadJpxBitmap(); + m_pCachedBitmap = LoadJpxBitmap(resolution_levels_to_skip); return m_pCachedBitmap ? LoadState::kSuccess : LoadState::kFail; } if (decoder == "JBIG2Decode") { m_pCachedBitmap = pdfium::MakeRetain<CFX_DIBitmap>(); if (!m_pCachedBitmap->Create( - m_Width, m_Height, m_bImageMask ? FXDIB_1bppMask : FXDIB_1bppRgb)) { + m_Width, m_Height, + m_bImageMask ? FXDIB_Format::k1bppMask : FXDIB_Format::k1bppRgb)) { m_pCachedBitmap.Reset(); return LoadState::kFail; } @@ -510,7 +530,7 @@ } pdfium::span<const uint8_t> src_span = m_pStreamAcc->GetSpan(); - const CPDF_Dictionary* pParams = m_pStreamAcc->GetImageParam(); + RetainPtr<const CPDF_Dictionary> pParams = m_pStreamAcc->GetImageParam(); if (decoder == "CCITTFaxDecode") { m_pDecoder = CreateFaxDecoder(src_span, m_Width, m_Height, pParams); } else if (decoder == "FlateDecode") { @@ -526,34 +546,33 @@ if (!m_pDecoder) return LoadState::kFail; - FX_SAFE_UINT32 requested_pitch = - fxcodec::CalculatePitch8(m_bpc, m_nComponents, m_Width); - if (!requested_pitch.IsValid()) + const absl::optional<uint32_t> requested_pitch = + fxge::CalculatePitch8(m_bpc, m_nComponents, m_Width); + if (!requested_pitch.has_value()) return LoadState::kFail; - FX_SAFE_UINT32 provided_pitch = fxcodec::CalculatePitch8( + const absl::optional<uint32_t> provided_pitch = fxge::CalculatePitch8( m_pDecoder->GetBPC(), m_pDecoder->CountComps(), m_pDecoder->GetWidth()); - if (!provided_pitch.IsValid()) + if (!provided_pitch.has_value()) return LoadState::kFail; - if (provided_pitch.ValueOrDie() < requested_pitch.ValueOrDie()) + if (provided_pitch.value() < requested_pitch.value()) return LoadState::kFail; return LoadState::kSuccess; } bool CPDF_DIB::CreateDCTDecoder(pdfium::span<const uint8_t> src_span, const CPDF_Dictionary* pParams) { - JpegModule* pJpegModule = fxcodec::ModuleMgr::GetInstance()->GetJpegModule(); - m_pDecoder = pJpegModule->CreateDecoder( + m_pDecoder = JpegModule::CreateDecoder( src_span, m_Width, m_Height, m_nComponents, !pParams || pParams->GetIntegerFor("ColorTransform", 1)); if (m_pDecoder) return true; - Optional<JpegModule::JpegImageInfo> info_opt = - pJpegModule->LoadInfo(src_span); + absl::optional<JpegModule::ImageInfo> info_opt = + JpegModule::LoadInfo(src_span); if (!info_opt.has_value()) return false; - const JpegModule::JpegImageInfo& info = info_opt.value(); + const JpegModule::ImageInfo& info = info_opt.value(); m_Width = info.width; m_Height = info.height; @@ -564,8 +583,8 @@ if (m_nComponents == static_cast<uint32_t>(info.num_components)) { m_bpc = info.bits_per_components; - m_pDecoder = pJpegModule->CreateDecoder( - src_span, m_Width, m_Height, m_nComponents, info.color_transform); + m_pDecoder = JpegModule::CreateDecoder(src_span, m_Width, m_Height, + m_nComponents, info.color_transform); return true; } @@ -574,20 +593,20 @@ if (m_pColorSpace) { uint32_t colorspace_comps = m_pColorSpace->CountComponents(); switch (m_Family) { - case PDFCS_DEVICEGRAY: - case PDFCS_DEVICERGB: - case PDFCS_DEVICECMYK: { + case CPDF_ColorSpace::Family::kDeviceGray: + case CPDF_ColorSpace::Family::kDeviceRGB: + case CPDF_ColorSpace::Family::kDeviceCMYK: { uint32_t dwMinComps = CPDF_ColorSpace::ComponentsForFamily(m_Family); if (colorspace_comps < dwMinComps || m_nComponents < dwMinComps) return false; break; } - case PDFCS_LAB: { + case CPDF_ColorSpace::Family::kLab: { if (m_nComponents != 3 || colorspace_comps < 3) return false; break; } - case PDFCS_ICCBASED: { + case CPDF_ColorSpace::Family::kICCBased: { if (!CPDF_ColorSpace::IsValidIccComponents(colorspace_comps) || !CPDF_ColorSpace::IsValidIccComponents(m_nComponents) || colorspace_comps < m_nComponents) { @@ -602,25 +621,30 @@ } } } else { - if (m_Family == PDFCS_LAB && m_nComponents != 3) + if (m_Family == CPDF_ColorSpace::Family::kLab && m_nComponents != 3) return false; } - if (!GetDecodeAndMaskArray(&m_bDefaultDecode, &m_bColorKey)) + if (!GetDecodeAndMaskArray()) return false; m_bpc = info.bits_per_components; - m_pDecoder = pJpegModule->CreateDecoder(src_span, m_Width, m_Height, - m_nComponents, info.color_transform); + m_pDecoder = JpegModule::CreateDecoder(src_span, m_Width, m_Height, + m_nComponents, info.color_transform); return true; } -RetainPtr<CFX_DIBitmap> CPDF_DIB::LoadJpxBitmap() { - std::unique_ptr<CJPX_Decoder> decoder = JpxModule::CreateDecoder( - m_pStreamAcc->GetSpan(), - ColorSpaceOptionFromColorSpace(m_pColorSpace.Get())); +RetainPtr<CFX_DIBitmap> CPDF_DIB::LoadJpxBitmap( + uint8_t resolution_levels_to_skip) { + std::unique_ptr<CJPX_Decoder> decoder = + CJPX_Decoder::Create(m_pStreamAcc->GetSpan(), + ColorSpaceOptionFromColorSpace(m_pColorSpace.Get()), + resolution_levels_to_skip); if (!decoder) return nullptr; + m_Height >>= resolution_levels_to_skip; + m_Width >>= resolution_levels_to_skip; + if (!decoder->StartDecode()) return nullptr; @@ -632,22 +656,35 @@ RetainPtr<CPDF_ColorSpace> original_colorspace = m_pColorSpace; bool swap_rgb = false; - switch (GetJpxDecodeAction(image_info.components, m_pColorSpace.Get())) { + bool convert_argb_to_rgb = false; + auto action = GetJpxDecodeAction(image_info, m_pColorSpace.Get()); + switch (action) { case JpxDecodeAction::kFail: return nullptr; case JpxDecodeAction::kDoNothing: break; + case JpxDecodeAction::kUseGray: + m_pColorSpace = + CPDF_ColorSpace::GetStockCS(CPDF_ColorSpace::Family::kDeviceGray); + break; + case JpxDecodeAction::kUseRgb: - DCHECK(image_info.components >= 3); + DCHECK(image_info.channels >= 3); swap_rgb = true; m_pColorSpace = nullptr; break; case JpxDecodeAction::kUseCmyk: - m_pColorSpace = CPDF_ColorSpace::GetStockCS(PDFCS_DEVICECMYK); + m_pColorSpace = + CPDF_ColorSpace::GetStockCS(CPDF_ColorSpace::Family::kDeviceCMYK); break; + + case JpxDecodeAction::kConvertArgbToRgb: + swap_rgb = true; + convert_argb_to_rgb = true; + m_pColorSpace.Reset(); } // If |original_colorspace| exists, then LoadColorInfo() already set @@ -656,19 +693,25 @@ DCHECK_NE(0, m_nComponents); } else { DCHECK_EQ(0, m_nComponents); - m_nComponents = image_info.components; + m_nComponents = GetComponentCountFromOpjColorSpace(image_info.colorspace); + if (m_nComponents == 0) { + return nullptr; + } } FXDIB_Format format; - if (image_info.components == 1) { - format = FXDIB_8bppRgb; - } else if (image_info.components <= 3) { - format = FXDIB_Rgb; - } else if (image_info.components == 4) { - format = FXDIB_Rgb32; + if (action == JpxDecodeAction::kUseGray) { + format = FXDIB_Format::k8bppRgb; + } else if (action == JpxDecodeAction::kUseRgb && image_info.channels == 3) { + format = FXDIB_Format::kRgb; + } else if (action == JpxDecodeAction::kConvertArgbToRgb && + image_info.channels == 4) { + format = FXDIB_Format::kRgb32; + } else if (action == JpxDecodeAction::kUseRgb && image_info.channels == 4) { + format = FXDIB_Format::kRgb32; } else { - image_info.width = (image_info.width * image_info.components + 2) / 3; - format = FXDIB_Rgb; + image_info.width = (image_info.width * image_info.channels + 2) / 3; + format = FXDIB_Format::kRgb; } auto result_bitmap = pdfium::MakeRetain<CFX_DIBitmap>(); @@ -677,44 +720,143 @@ result_bitmap->Clear(0xFFFFFFFF); if (!decoder->Decode(result_bitmap->GetBuffer(), result_bitmap->GetPitch(), - swap_rgb)) { + swap_rgb, m_nComponents)) { return nullptr; } - if (m_pColorSpace && m_pColorSpace->GetFamily() == PDFCS_INDEXED && - m_bpc < 8) { + if (convert_argb_to_rgb) { + DCHECK_EQ(3, m_nComponents); + auto rgb_bitmap = pdfium::MakeRetain<CFX_DIBitmap>(); + if (!rgb_bitmap->Create(image_info.width, image_info.height, + FXDIB_Format::kRgb)) { + return nullptr; + } + if (m_pDict->GetIntegerFor("SMaskInData") == 1) { + // TODO(thestig): Acrobat does not support "/SMaskInData 1" combined with + // filters. Check for that and fail early. + DCHECK(m_JpxInlineData.data.empty()); + m_JpxInlineData.width = image_info.width; + m_JpxInlineData.height = image_info.height; + m_JpxInlineData.data.reserve(image_info.width * image_info.height); + for (uint32_t row = 0; row < image_info.height; ++row) { + const uint8_t* src = result_bitmap->GetScanline(row).data(); + uint8_t* dest = rgb_bitmap->GetWritableScanline(row).data(); + for (uint32_t col = 0; col < image_info.width; ++col) { + uint8_t a = src[3]; + m_JpxInlineData.data.push_back(a); + uint8_t na = 255 - a; + uint8_t b = (src[0] * a + 255 * na) / 255; + uint8_t g = (src[1] * a + 255 * na) / 255; + uint8_t r = (src[2] * a + 255 * na) / 255; + dest[0] = b; + dest[1] = g; + dest[2] = r; + src += 4; + dest += 3; + } + } + } else { + // TODO(thestig): Is there existing code that does this already? + for (uint32_t row = 0; row < image_info.height; ++row) { + const uint8_t* src = result_bitmap->GetScanline(row).data(); + uint8_t* dest = rgb_bitmap->GetWritableScanline(row).data(); + for (uint32_t col = 0; col < image_info.width; ++col) { + memcpy(dest, src, 3); + src += 4; + dest += 3; + } + } + } + result_bitmap = std::move(rgb_bitmap); + } else if (m_pColorSpace && + m_pColorSpace->GetFamily() == CPDF_ColorSpace::Family::kIndexed && + m_bpc < 8) { int scale = 8 - m_bpc; for (uint32_t row = 0; row < image_info.height; ++row) { - uint8_t* scanline = result_bitmap->GetWritableScanline(row); + uint8_t* scanline = result_bitmap->GetWritableScanline(row).data(); for (uint32_t col = 0; col < image_info.width; ++col) { *scanline = (*scanline) >> scale; ++scanline; } } } + + // TODO(crbug.com/pdfium/1747): Handle SMaskInData entries for different + // color space types. + m_bpc = 8; return result_bitmap; } +bool CPDF_DIB::LoadInternal(const CPDF_Dictionary* pFormResources, + const CPDF_Dictionary* pPageResources) { + if (!m_pStream) + return false; + + m_pDict = m_pStream->GetDict(); + if (!m_pDict) + return false; + + m_Width = m_pDict->GetIntegerFor("Width"); + m_Height = m_pDict->GetIntegerFor("Height"); + if (!IsValidDimension(m_Width) || !IsValidDimension(m_Height)) + return false; + + if (!LoadColorInfo(pFormResources, pPageResources)) + return false; + + if (m_bDoBpcCheck && (m_bpc == 0 || m_nComponents == 0)) + return false; + + const absl::optional<uint32_t> maybe_size = + fxge::CalculatePitch8(m_bpc, m_nComponents, m_Width); + if (!maybe_size.has_value()) + return false; + + FX_SAFE_UINT32 src_size = maybe_size.value(); + src_size *= m_Height; + if (!src_size.IsValid()) + return false; + + m_pStreamAcc = pdfium::MakeRetain<CPDF_StreamAcc>(m_pStream); + m_pStreamAcc->LoadAllDataImageAcc(src_size.ValueOrDie()); + return !m_pStreamAcc->GetSpan().empty(); +} + CPDF_DIB::LoadState CPDF_DIB::StartLoadMask() { m_MatteColor = 0XFFFFFFFF; + + if (!m_JpxInlineData.data.empty()) { + auto dict = pdfium::MakeRetain<CPDF_Dictionary>(); + dict->SetNewFor<CPDF_Name>("Type", "XObject"); + dict->SetNewFor<CPDF_Name>("Subtype", "Image"); + dict->SetNewFor<CPDF_Name>("ColorSpace", "DeviceGray"); + dict->SetNewFor<CPDF_Number>("Width", m_JpxInlineData.width); + dict->SetNewFor<CPDF_Number>("Height", m_JpxInlineData.height); + dict->SetNewFor<CPDF_Number>("BitsPerComponent", 8); + + return StartLoadMaskDIB( + pdfium::MakeRetain<CPDF_Stream>(m_JpxInlineData.data, std::move(dict))); + } + RetainPtr<const CPDF_Stream> mask(m_pDict->GetStreamFor("SMask")); if (!mask) { - mask.Reset(ToStream(m_pDict->GetDirectObjectFor("Mask"))); + mask = ToStream(m_pDict->GetDirectObjectFor("Mask")); return mask ? StartLoadMaskDIB(std::move(mask)) : LoadState::kSuccess; } - const CPDF_Array* pMatte = mask->GetDict()->GetArrayFor("Matte"); - if (pMatte && m_pColorSpace && m_Family != PDFCS_PATTERN && + RetainPtr<const CPDF_Array> pMatte = mask->GetDict()->GetArrayFor("Matte"); + if (pMatte && m_pColorSpace && + m_Family != CPDF_ColorSpace::Family::kPattern && pMatte->size() == m_nComponents && m_pColorSpace->CountComponents() <= m_nComponents) { std::vector<float> colors = - ReadArrayElementsToVector(pMatte, m_nComponents); + ReadArrayElementsToVector(pMatte.Get(), m_nComponents); float R; float G; float B; - m_pColorSpace->GetRGB(colors.data(), &R, &G, &B); + m_pColorSpace->GetRGB(colors, &R, &G, &B); m_MatteColor = ArgbEncode(0, FXSYS_roundf(R * 255), FXSYS_roundf(G * 255), FXSYS_roundf(B * 255)); } @@ -748,10 +890,11 @@ } CPDF_DIB::LoadState CPDF_DIB::StartLoadMaskDIB( - RetainPtr<const CPDF_Stream> mask) { - m_pMask = pdfium::MakeRetain<CPDF_DIB>(); - LoadState ret = m_pMask->StartLoadDIBBase( - m_pDocument.Get(), mask.Get(), false, nullptr, nullptr, true, 0, false); + RetainPtr<const CPDF_Stream> mask_stream) { + m_pMask = pdfium::MakeRetain<CPDF_DIB>(m_pDocument, std::move(mask_stream)); + LoadState ret = m_pMask->StartLoadDIBBase(false, nullptr, nullptr, true, + CPDF_ColorSpace::Family::kUnknown, + false, {0, 0}); if (ret == LoadState::kContinue) { if (m_Status == LoadState::kFail) m_Status = LoadState::kContinue; @@ -763,7 +906,7 @@ } void CPDF_DIB::LoadPalette() { - if (!m_pColorSpace || m_Family == PDFCS_PATTERN) + if (!m_pColorSpace || m_Family == CPDF_ColorSpace::Family::kPattern) return; if (m_bpc == 0) @@ -778,17 +921,16 @@ return; if (bits == 1) { - if (m_bDefaultDecode && - (m_Family == PDFCS_DEVICEGRAY || m_Family == PDFCS_DEVICERGB)) { + if (m_bDefaultDecode && (m_Family == CPDF_ColorSpace::Family::kDeviceGray || + m_Family == CPDF_ColorSpace::Family::kDeviceRGB)) { return; } if (m_pColorSpace->CountComponents() > 3) { return; } float color_values[3]; - color_values[0] = m_CompData[0].m_DecodeMin; - color_values[1] = color_values[0]; - color_values[2] = color_values[0]; + std::fill(std::begin(color_values), std::end(color_values), + m_CompData[0].m_DecodeMin); float R = 0.0f; float G = 0.0f; @@ -797,12 +939,22 @@ FX_ARGB argb0 = ArgbEncode(255, FXSYS_roundf(R * 255), FXSYS_roundf(G * 255), FXSYS_roundf(B * 255)); - color_values[0] += m_CompData[0].m_DecodeStep; - color_values[1] += m_CompData[0].m_DecodeStep; - color_values[2] += m_CompData[0].m_DecodeStep; - m_pColorSpace->GetRGB(color_values, &R, &G, &B); - FX_ARGB argb1 = ArgbEncode(255, FXSYS_roundf(R * 255), - FXSYS_roundf(G * 255), FXSYS_roundf(B * 255)); + FX_ARGB argb1; + const CPDF_IndexedCS* indexed_cs = m_pColorSpace->AsIndexedCS(); + if (indexed_cs && indexed_cs->GetMaxIndex() == 0) { + // If an indexed color space's hival value is 0, only 1 color is specified + // in the lookup table. Another color should be set to 0xFF000000 by + // default to set the range of the color space. + argb1 = 0xFF000000; + } else { + color_values[0] += m_CompData[0].m_DecodeStep; + color_values[1] += m_CompData[0].m_DecodeStep; + color_values[2] += m_CompData[0].m_DecodeStep; + m_pColorSpace->GetRGB(color_values, &R, &G, &B); + argb1 = ArgbEncode(255, FXSYS_roundf(R * 255), FXSYS_roundf(G * 255), + FXSYS_roundf(B * 255)); + } + if (argb0 != 0xFF000000 || argb1 != 0xFFFFFFFF) { SetPaletteArgb(0, argb0); SetPaletteArgb(1, argb1); @@ -810,7 +962,8 @@ return; } if (m_bpc == 8 && m_bDefaultDecode && - m_pColorSpace == CPDF_ColorSpace::GetStockCS(PDFCS_DEVICEGRAY)) { + m_pColorSpace == + CPDF_ColorSpace::GetStockCS(CPDF_ColorSpace::Family::kDeviceGray)) { return; } @@ -828,56 +981,49 @@ float R = 0; float G = 0; float B = 0; - if (m_nComponents == 1 && m_Family == PDFCS_ICCBASED && + if (m_nComponents == 1 && m_Family == CPDF_ColorSpace::Family::kICCBased && m_pColorSpace->CountComponents() > 1) { int nComponents = m_pColorSpace->CountComponents(); std::vector<float> temp_buf(nComponents); for (int k = 0; k < nComponents; ++k) temp_buf[k] = color_values[0]; - m_pColorSpace->GetRGB(temp_buf.data(), &R, &G, &B); + m_pColorSpace->GetRGB(temp_buf, &R, &G, &B); } else { - m_pColorSpace->GetRGB(color_values.data(), &R, &G, &B); + m_pColorSpace->GetRGB(color_values, &R, &G, &B); } SetPaletteArgb(i, ArgbEncode(255, FXSYS_roundf(R * 255), FXSYS_roundf(G * 255), FXSYS_roundf(B * 255))); } } -void CPDF_DIB::ValidateDictParam() { +bool CPDF_DIB::ValidateDictParam(const ByteString& filter) { m_bpc = m_bpc_orig; - const CPDF_Object* pFilter = m_pDict->GetDirectObjectFor("Filter"); - if (pFilter) { - if (pFilter->IsName()) { - ByteString filter = pFilter->GetString(); - if (filter == "CCITTFaxDecode" || filter == "JBIG2Decode") { - m_bpc = 1; - m_nComponents = 1; - } else if (filter == "RunLengthDecode") { - if (m_bpc != 1) { - m_bpc = 8; - } - } else if (filter == "DCTDecode") { - m_bpc = 8; - } - } else if (const CPDF_Array* pArray = pFilter->AsArray()) { - ByteString filter = pArray->GetStringAt(pArray->size() - 1); - if (filter == "CCITTFaxDecode" || filter == "JBIG2Decode") { - m_bpc = 1; - m_nComponents = 1; - } else if (filter == "DCTDecode") { - // Previously, filter == "RunLengthDecode" was checked in the "if" - // statement as well, but too many documents don't conform to it. - m_bpc = 8; - } - } + + // Per spec, |m_bpc| should always be 8 for RunLengthDecode, but too many + // documents do not conform to it. So skip this check. + + if (filter == "JPXDecode") { + m_bDoBpcCheck = false; + return true; } - if (!IsAllowedBitsPerComponent(m_bpc)) + if (filter == "CCITTFaxDecode" || filter == "JBIG2Decode") { + m_bpc = 1; + m_nComponents = 1; + } else if (filter == "DCTDecode") { + m_bpc = 8; + } + + if (!IsAllowedBitsPerComponent(m_bpc)) { m_bpc = 0; + return false; + } + return true; } -void CPDF_DIB::TranslateScanline24bpp(uint8_t* dest_scan, - const uint8_t* src_scan) const { +void CPDF_DIB::TranslateScanline24bpp( + pdfium::span<uint8_t> dest_scan, + pdfium::span<const uint8_t> src_scan) const { if (m_bpc == 0) return; @@ -900,7 +1046,7 @@ color_values[color] = m_CompData[color].m_DecodeMin + m_CompData[color].m_DecodeStep * data; } else { - unsigned int data = GetBits8(src_scan, src_bit_pos, m_bpc); + unsigned int data = GetBits8(src_scan.data(), src_bit_pos, m_bpc); color_values[color] = m_CompData[color].m_DecodeMin + m_CompData[color].m_DecodeStep * data; src_bit_pos += m_bpc; @@ -912,8 +1058,8 @@ R = (1.0f - color_values[0]) * k; G = (1.0f - color_values[1]) * k; B = (1.0f - color_values[2]) * k; - } else if (m_Family != PDFCS_PATTERN) { - m_pColorSpace->GetRGB(color_values.data(), &R, &G, &B); + } else if (m_Family != CPDF_ColorSpace::Family::kPattern) { + m_pColorSpace->GetRGB(color_values, &R, &G, &B); } R = pdfium::clamp(R, 0.0f, 1.0f); G = pdfium::clamp(G, 0.0f, 1.0f); @@ -926,12 +1072,13 @@ } bool CPDF_DIB::TranslateScanline24bppDefaultDecode( - uint8_t* dest_scan, - const uint8_t* src_scan) const { + pdfium::span<uint8_t> dest_scan, + pdfium::span<const uint8_t> src_scan) const { if (!m_bDefaultDecode) return false; - if (m_Family != PDFCS_DEVICERGB && m_Family != PDFCS_CALRGB) { + if (m_Family != CPDF_ColorSpace::Family::kDeviceRGB && + m_Family != CPDF_ColorSpace::Family::kCalRGB) { if (m_bpc != 8) return false; @@ -945,21 +1092,22 @@ if (m_nComponents != 3) return true; - const uint8_t* src_pos = src_scan; + uint8_t* dest_pos = dest_scan.data(); + const uint8_t* src_pos = src_scan.data(); switch (m_bpc) { case 8: for (int column = 0; column < m_Width; column++) { - *dest_scan++ = src_pos[2]; - *dest_scan++ = src_pos[1]; - *dest_scan++ = *src_pos; + *dest_pos++ = src_pos[2]; + *dest_pos++ = src_pos[1]; + *dest_pos++ = *src_pos; src_pos += 3; } break; case 16: for (int col = 0; col < m_Width; col++) { - *dest_scan++ = src_pos[4]; - *dest_scan++ = src_pos[2]; - *dest_scan++ = *src_pos; + *dest_pos++ = src_pos[4]; + *dest_pos++ = src_pos[2]; + *dest_pos++ = *src_pos; src_pos += 6; } break; @@ -968,18 +1116,18 @@ uint64_t src_bit_pos = 0; size_t dest_byte_pos = 0; for (int column = 0; column < m_Width; column++) { - unsigned int R = GetBits8(src_scan, src_bit_pos, m_bpc); + unsigned int R = GetBits8(src_scan.data(), src_bit_pos, m_bpc); src_bit_pos += m_bpc; - unsigned int G = GetBits8(src_scan, src_bit_pos, m_bpc); + unsigned int G = GetBits8(src_scan.data(), src_bit_pos, m_bpc); src_bit_pos += m_bpc; - unsigned int B = GetBits8(src_scan, src_bit_pos, m_bpc); + unsigned int B = GetBits8(src_scan.data(), src_bit_pos, m_bpc); src_bit_pos += m_bpc; R = std::min(R, max_data); G = std::min(G, max_data); B = std::min(B, max_data); - dest_scan[dest_byte_pos] = B * 255 / max_data; - dest_scan[dest_byte_pos + 1] = G * 255 / max_data; - dest_scan[dest_byte_pos + 2] = R * 255 / max_data; + dest_pos[dest_byte_pos] = B * 255 / max_data; + dest_pos[dest_byte_pos + 1] = G * 255 / max_data; + dest_pos[dest_byte_pos + 2] = R * 255 / max_data; dest_byte_pos += 3; } break; @@ -987,424 +1135,175 @@ return true; } -uint8_t* CPDF_DIB::GetBuffer() const { - return m_pCachedBitmap ? m_pCachedBitmap->GetBuffer() : nullptr; +pdfium::span<uint8_t> CPDF_DIB::GetBuffer() const { + return m_pCachedBitmap ? m_pCachedBitmap->GetBuffer() + : pdfium::span<uint8_t>(); } -const uint8_t* CPDF_DIB::GetScanline(int line) const { +pdfium::span<const uint8_t> CPDF_DIB::GetScanline(int line) const { if (m_bpc == 0) - return nullptr; + return pdfium::span<const uint8_t>(); - FX_SAFE_UINT32 src_pitch = - fxcodec::CalculatePitch8(m_bpc, m_nComponents, m_Width); - if (!src_pitch.IsValid()) - return nullptr; - uint32_t src_pitch_value = src_pitch.ValueOrDie(); + const absl::optional<uint32_t> src_pitch = + fxge::CalculatePitch8(m_bpc, m_nComponents, m_Width); + if (!src_pitch.has_value()) + return pdfium::span<const uint8_t>(); - const uint8_t* pSrcLine = nullptr; + uint32_t src_pitch_value = src_pitch.value(); + // This is used as the buffer of `pSrcLine` when the stream is truncated, + // and the remaining bytes count is less than `src_pitch_value` + DataVector<uint8_t> temp_buffer; + pdfium::span<const uint8_t> pSrcLine; + if (m_pCachedBitmap && src_pitch_value <= m_pCachedBitmap->GetPitch()) { - if (line >= m_pCachedBitmap->GetHeight()) { + if (line >= m_pCachedBitmap->GetHeight()) line = m_pCachedBitmap->GetHeight() - 1; - } pSrcLine = m_pCachedBitmap->GetScanline(line); } else if (m_pDecoder) { pSrcLine = m_pDecoder->GetScanline(line); - } else if (m_pStreamAcc->GetSize() >= (line + 1) * src_pitch_value) { - pSrcLine = m_pStreamAcc->GetData() + line * src_pitch_value; - } - if (!pSrcLine) { - uint8_t* pLineBuf = m_pMaskedLine ? m_pMaskedLine.get() : m_pLineBuf.get(); - memset(pLineBuf, 0xFF, m_Pitch); - return pLineBuf; + } else if (m_pStreamAcc->GetSize() > line * src_pitch_value) { + pdfium::span<const uint8_t> remaining_bytes = + m_pStreamAcc->GetSpan().subspan(line * src_pitch_value); + if (remaining_bytes.size() >= src_pitch_value) { + pSrcLine = remaining_bytes.first(src_pitch_value); + } else { + temp_buffer = DataVector<uint8_t>(src_pitch_value); + pdfium::span<uint8_t> result = temp_buffer; + fxcrt::spancpy(result, remaining_bytes); + pSrcLine = result; + } } + if (pSrcLine.empty()) { + pdfium::span<uint8_t> result = !m_MaskBuf.empty() ? m_MaskBuf : m_LineBuf; + fxcrt::spanset(result, 0); + return result; + } if (m_bpc * m_nComponents == 1) { if (m_bImageMask && m_bDefaultDecode) { - for (uint32_t i = 0; i < src_pitch_value; i++) - m_pLineBuf.get()[i] = ~pSrcLine[i]; - return m_pLineBuf.get(); + for (uint32_t i = 0; i < src_pitch_value; i++) { + // TODO(tsepez): Bounds check if cost is acceptable. + m_LineBuf[i] = ~pSrcLine.data()[i]; + } + return pdfium::make_span(m_LineBuf).first(src_pitch_value); } - if (!m_bColorKey) { - memcpy(m_pLineBuf.get(), pSrcLine, src_pitch_value); - return m_pLineBuf.get(); + pdfium::span<uint8_t> result = m_LineBuf; + fxcrt::spancpy(result, pSrcLine.first(src_pitch_value)); + return result.first(src_pitch_value); } - - uint32_t reset_argb = m_pPalette ? m_pPalette.get()[0] : 0xFF000000; - uint32_t set_argb = m_pPalette ? m_pPalette.get()[1] : 0xFFFFFFFF; - if (m_CompData[0].m_ColorKeyMin == 0) - reset_argb = 0; - if (m_CompData[0].m_ColorKeyMax == 1) - set_argb = 0; - set_argb = FXARGB_TODIB(set_argb); - reset_argb = FXARGB_TODIB(reset_argb); - uint32_t* dest_scan = reinterpret_cast<uint32_t*>(m_pMaskedLine.get()); - for (int col = 0; col < m_Width; col++) { - *dest_scan = GetBitValue(pSrcLine, col) ? set_argb : reset_argb; - dest_scan++; + uint32_t reset_argb = Get1BitResetValue(); + uint32_t set_argb = Get1BitSetValue(); + uint32_t* dest_scan = reinterpret_cast<uint32_t*>(m_MaskBuf.data()); + for (int col = 0; col < m_Width; col++, dest_scan++) { + *dest_scan = GetBitValue(pSrcLine.data(), col) ? set_argb : reset_argb; } - return m_pMaskedLine.get(); + return pdfium::make_span(m_MaskBuf).first(m_Width * sizeof(uint32_t)); } if (m_bpc * m_nComponents <= 8) { + pdfium::span<uint8_t> result = m_LineBuf; if (m_bpc == 8) { - memcpy(m_pLineBuf.get(), pSrcLine, src_pitch_value); + fxcrt::spancpy(result, pSrcLine.first(src_pitch_value)); + result = result.first(src_pitch_value); } else { uint64_t src_bit_pos = 0; for (int col = 0; col < m_Width; col++) { unsigned int color_index = 0; for (uint32_t color = 0; color < m_nComponents; color++) { - unsigned int data = GetBits8(pSrcLine, src_bit_pos, m_bpc); + unsigned int data = GetBits8(pSrcLine.data(), src_bit_pos, m_bpc); color_index |= data << (color * m_bpc); src_bit_pos += m_bpc; } - m_pLineBuf.get()[col] = color_index; + m_LineBuf[col] = color_index; } + result = result.first(m_Width); } if (!m_bColorKey) - return m_pLineBuf.get(); + return result; - uint8_t* pDestPixel = m_pMaskedLine.get(); - const uint8_t* pSrcPixel = m_pLineBuf.get(); - for (int col = 0; col < m_Width; col++) { - uint8_t index = *pSrcPixel++; - if (m_pPalette) { - *pDestPixel++ = FXARGB_B(m_pPalette.get()[index]); - *pDestPixel++ = FXARGB_G(m_pPalette.get()[index]); - *pDestPixel++ = FXARGB_R(m_pPalette.get()[index]); - } else { - *pDestPixel++ = index; - *pDestPixel++ = index; - *pDestPixel++ = index; + uint8_t* pDestPixel = m_MaskBuf.data(); + const uint8_t* pSrcPixel = m_LineBuf.data(); + pdfium::span<const uint32_t> palette = GetPaletteSpan(); + if (HasPalette()) { + for (int col = 0; col < m_Width; col++) { + uint8_t index = *pSrcPixel++; + *pDestPixel++ = FXARGB_B(palette[index]); + *pDestPixel++ = FXARGB_G(palette[index]); + *pDestPixel++ = FXARGB_R(palette[index]); + *pDestPixel++ = + IsColorIndexOutOfBounds(index, m_CompData[0]) ? 0xFF : 0; } - *pDestPixel = IsColorIndexOutOfBounds(index, m_CompData[0]) ? 0xFF : 0; - pDestPixel++; + } else { + for (int col = 0; col < m_Width; col++) { + uint8_t index = *pSrcPixel++; + *pDestPixel++ = index; + *pDestPixel++ = index; + *pDestPixel++ = index; + *pDestPixel++ = + IsColorIndexOutOfBounds(index, m_CompData[0]) ? 0xFF : 0; + } } - return m_pMaskedLine.get(); + return pdfium::make_span(m_MaskBuf).first(4 * m_Width); } if (m_bColorKey) { if (m_nComponents == 3 && m_bpc == 8) { - uint8_t* alpha_channel = m_pMaskedLine.get() + 3; + uint8_t* alpha_channel = m_MaskBuf.data() + 3; for (int col = 0; col < m_Width; col++) { - const uint8_t* pPixel = pSrcLine + col * 3; + const uint8_t* pPixel = pSrcLine.data() + col * 3; alpha_channel[col * 4] = AreColorIndicesOutOfBounds(pPixel, m_CompData.data(), 3) ? 0xFF : 0; } } else { - memset(m_pMaskedLine.get(), 0xFF, m_Pitch); + fxcrt::spanset(pdfium::make_span(m_MaskBuf), 0xFF); } } if (m_pColorSpace) { - TranslateScanline24bpp(m_pLineBuf.get(), pSrcLine); - pSrcLine = m_pLineBuf.get(); + TranslateScanline24bpp(m_LineBuf, pSrcLine); + src_pitch_value = 3 * m_Width; + pSrcLine = pdfium::make_span(m_LineBuf).first(src_pitch_value); } if (!m_bColorKey) return pSrcLine; - const uint8_t* pSrcPixel = pSrcLine; - uint8_t* pDestPixel = m_pMaskedLine.get(); + // TODO(tsepez): Bounds check if cost is acceptable. + const uint8_t* pSrcPixel = pSrcLine.data(); + uint8_t* pDestPixel = m_MaskBuf.data(); for (int col = 0; col < m_Width; col++) { *pDestPixel++ = *pSrcPixel++; *pDestPixel++ = *pSrcPixel++; *pDestPixel++ = *pSrcPixel++; pDestPixel++; } - return m_pMaskedLine.get(); + return pdfium::make_span(m_MaskBuf).first(4 * m_Width); } bool CPDF_DIB::SkipToScanline(int line, PauseIndicatorIface* pPause) const { return m_pDecoder && m_pDecoder->SkipToScanline(line, pPause); } -void CPDF_DIB::DownSampleScanline(int line, - uint8_t* dest_scan, - int dest_bpp, - int dest_width, - bool bFlipX, - int clip_left, - int clip_width) const { - if (line < 0 || !dest_scan || dest_bpp <= 0 || dest_width <= 0 || - clip_left < 0 || clip_width <= 0) { - return; - } - - uint32_t src_width = m_Width; - FX_SAFE_UINT32 pitch = - fxcodec::CalculatePitch8(m_bpc, m_nComponents, m_Width); - if (!pitch.IsValid()) - return; - - const uint8_t* pSrcLine = nullptr; - if (m_pCachedBitmap) { - pSrcLine = m_pCachedBitmap->GetScanline(line); - } else if (m_pDecoder) { - pSrcLine = m_pDecoder->GetScanline(line); - } else { - uint32_t src_pitch = pitch.ValueOrDie(); - pitch *= (line + 1); - if (!pitch.IsValid()) { - return; - } - - if (m_pStreamAcc->GetSize() >= pitch.ValueOrDie()) { - pSrcLine = m_pStreamAcc->GetData() + line * src_pitch; - } - } - int orig_Bpp = m_bpc * m_nComponents / 8; - int dest_Bpp = dest_bpp / 8; - if (!pSrcLine) { - memset(dest_scan, 0xFF, dest_Bpp * clip_width); - return; - } - - FX_SAFE_INT32 max_src_x = clip_left; - max_src_x += clip_width - 1; - max_src_x *= src_width; - max_src_x /= dest_width; - if (!max_src_x.IsValid()) - return; - - if (m_bpc * m_nComponents == 1) { - DownSampleScanline1Bit(orig_Bpp, dest_Bpp, src_width, pSrcLine, dest_scan, - dest_width, bFlipX, clip_left, clip_width); - } else if (m_bpc * m_nComponents <= 8) { - DownSampleScanline8Bit(orig_Bpp, dest_Bpp, src_width, pSrcLine, dest_scan, - dest_width, bFlipX, clip_left, clip_width); - } else { - DownSampleScanline32Bit(orig_Bpp, dest_Bpp, src_width, pSrcLine, dest_scan, - dest_width, bFlipX, clip_left, clip_width); - } -} - -void CPDF_DIB::DownSampleScanline1Bit(int orig_Bpp, - int dest_Bpp, - uint32_t src_width, - const uint8_t* pSrcLine, - uint8_t* dest_scan, - int dest_width, - bool bFlipX, - int clip_left, - int clip_width) const { - if (m_bColorKey && !m_bImageMask) { - uint32_t reset_argb = m_pPalette ? m_pPalette.get()[0] : 0xFF000000; - uint32_t set_argb = m_pPalette ? m_pPalette.get()[1] : 0xFFFFFFFF; - if (m_CompData[0].m_ColorKeyMin == 0) - reset_argb = 0; - if (m_CompData[0].m_ColorKeyMax == 1) - set_argb = 0; - set_argb = FXARGB_TODIB(set_argb); - reset_argb = FXARGB_TODIB(reset_argb); - uint32_t* dest_scan_dword = reinterpret_cast<uint32_t*>(dest_scan); - for (int i = 0; i < clip_width; i++) { - uint32_t src_x = (clip_left + i) * src_width / dest_width; - if (bFlipX) - src_x = src_width - src_x - 1; - src_x %= src_width; - dest_scan_dword[i] = GetBitValue(pSrcLine, src_x) ? set_argb : reset_argb; - } - return; - } - - uint32_t set_argb = 0xFFFFFFFF; - uint32_t reset_argb = 0; - if (m_bImageMask) { - if (m_bDefaultDecode) { - set_argb = 0; - reset_argb = 0xFFFFFFFF; - } - } else if (m_pPalette && dest_Bpp != 1) { - reset_argb = m_pPalette.get()[0]; - set_argb = m_pPalette.get()[1]; - } - for (int i = 0; i < clip_width; i++) { - uint32_t src_x = (clip_left + i) * src_width / dest_width; - if (bFlipX) - src_x = src_width - src_x - 1; - src_x %= src_width; - int dest_pos = i * dest_Bpp; - uint32_t value_argb = GetBitValue(pSrcLine, src_x) ? set_argb : reset_argb; - if (dest_Bpp == 1) { - dest_scan[dest_pos] = static_cast<uint8_t>(value_argb); - } else if (dest_Bpp == 3) { - dest_scan[dest_pos] = FXARGB_B(value_argb); - dest_scan[dest_pos + 1] = FXARGB_G(value_argb); - dest_scan[dest_pos + 2] = FXARGB_R(value_argb); - } else { - *reinterpret_cast<uint32_t*>(dest_scan + dest_pos) = value_argb; - } - } -} - -void CPDF_DIB::DownSampleScanline8Bit(int orig_Bpp, - int dest_Bpp, - uint32_t src_width, - const uint8_t* pSrcLine, - uint8_t* dest_scan, - int dest_width, - bool bFlipX, - int clip_left, - int clip_width) const { - if (m_bpc < 8) { - uint64_t src_bit_pos = 0; - for (uint32_t col = 0; col < src_width; col++) { - unsigned int color_index = 0; - for (uint32_t color = 0; color < m_nComponents; color++) { - unsigned int data = GetBits8(pSrcLine, src_bit_pos, m_bpc); - color_index |= data << (color * m_bpc); - src_bit_pos += m_bpc; - } - m_pLineBuf.get()[col] = color_index; - } - pSrcLine = m_pLineBuf.get(); - } - if (m_bColorKey) { - for (int i = 0; i < clip_width; i++) { - uint32_t src_x = (clip_left + i) * src_width / dest_width; - if (bFlipX) { - src_x = src_width - src_x - 1; - } - src_x %= src_width; - uint8_t* pDestPixel = dest_scan + i * 4; - uint8_t index = pSrcLine[src_x]; - if (m_pPalette) { - *pDestPixel++ = FXARGB_B(m_pPalette.get()[index]); - *pDestPixel++ = FXARGB_G(m_pPalette.get()[index]); - *pDestPixel++ = FXARGB_R(m_pPalette.get()[index]); - } else { - *pDestPixel++ = index; - *pDestPixel++ = index; - *pDestPixel++ = index; - } - *pDestPixel = (index < m_CompData[0].m_ColorKeyMin || - index > m_CompData[0].m_ColorKeyMax) - ? 0xFF - : 0; - } - return; - } - for (int i = 0; i < clip_width; i++) { - uint32_t src_x = (clip_left + i) * src_width / dest_width; - if (bFlipX) - src_x = src_width - src_x - 1; - src_x %= src_width; - uint8_t index = pSrcLine[src_x]; - if (dest_Bpp == 1) { - dest_scan[i] = index; - } else { - int dest_pos = i * dest_Bpp; - FX_ARGB argb = m_pPalette.get()[index]; - dest_scan[dest_pos] = FXARGB_B(argb); - dest_scan[dest_pos + 1] = FXARGB_G(argb); - dest_scan[dest_pos + 2] = FXARGB_R(argb); - } - } -} - -void CPDF_DIB::DownSampleScanline32Bit(int orig_Bpp, - int dest_Bpp, - uint32_t src_width, - const uint8_t* pSrcLine, - uint8_t* dest_scan, - int dest_width, - bool bFlipX, - int clip_left, - int clip_width) const { - // last_src_x used to store the last seen src_x position which should be - // in [0, src_width). Set the initial value to be an invalid src_x value. - uint32_t last_src_x = src_width; - FX_ARGB last_argb = ArgbEncode(0xFF, 0xFF, 0xFF, 0xFF); - float unit_To8Bpc = 255.0f / ((1 << m_bpc) - 1); - for (int i = 0; i < clip_width; i++) { - int dest_x = clip_left + i; - uint32_t src_x = (bFlipX ? (dest_width - dest_x - 1) : dest_x) * - (int64_t)src_width / dest_width; - src_x %= src_width; - - uint8_t* pDestPixel = dest_scan + i * dest_Bpp; - FX_ARGB argb; - if (src_x == last_src_x) { - argb = last_argb; - } else { - CFX_FixedBufGrow<uint8_t, 16> extracted_components(m_nComponents); - const uint8_t* pSrcPixel = nullptr; - if (m_bpc % 8 != 0) { - // No need to check for 32-bit overflow, as |src_x| is bounded by - // |src_width| and DownSampleScanline() already checked for overflow - // with the pitch calculation. - size_t num_bits = src_x * m_bpc * m_nComponents; - uint64_t src_bit_pos = num_bits % 8; - pSrcPixel = pSrcLine + num_bits / 8; - for (uint32_t j = 0; j < m_nComponents; ++j) { - extracted_components[j] = static_cast<uint8_t>( - GetBits8(pSrcPixel, src_bit_pos, m_bpc) * unit_To8Bpc); - src_bit_pos += m_bpc; - } - pSrcPixel = extracted_components; - } else { - pSrcPixel = pSrcLine + src_x * orig_Bpp; - if (m_bpc == 16) { - for (uint32_t j = 0; j < m_nComponents; ++j) - extracted_components[j] = pSrcPixel[j * 2]; - pSrcPixel = extracted_components; - } - } - - if (m_pColorSpace) { - uint8_t color[4]; - const bool bTransMask = TransMask(); - if (!m_bDefaultDecode) { - for (uint32_t j = 0; j < m_nComponents; ++j) { - float component_value = static_cast<float>(pSrcPixel[j]); - int color_value = static_cast<int>( - (m_CompData[j].m_DecodeMin + - m_CompData[j].m_DecodeStep * component_value) * - 255.0f + - 0.5f); - extracted_components[j] = pdfium::clamp(color_value, 0, 255); - } - } - const uint8_t* pSrc = - m_bDefaultDecode ? pSrcPixel : extracted_components; - m_pColorSpace->TranslateImageLine(color, pSrc, 1, 0, 0, bTransMask); - argb = ArgbEncode(0xFF, color[2], color[1], color[0]); - } else { - argb = ArgbEncode(0xFF, pSrcPixel[2], pSrcPixel[1], pSrcPixel[0]); - } - if (m_bColorKey) { - int alpha = 0xFF; - if (m_nComponents == 3 && m_bpc == 8) { - alpha = (pSrcPixel[0] < m_CompData[0].m_ColorKeyMin || - pSrcPixel[0] > m_CompData[0].m_ColorKeyMax || - pSrcPixel[1] < m_CompData[1].m_ColorKeyMin || - pSrcPixel[1] > m_CompData[1].m_ColorKeyMax || - pSrcPixel[2] < m_CompData[2].m_ColorKeyMin || - pSrcPixel[2] > m_CompData[2].m_ColorKeyMax) - ? 0xFF - : 0; - } - argb &= 0xFFFFFF; - argb |= alpha << 24; - } - last_src_x = src_x; - last_argb = argb; - } - if (dest_Bpp == 4) { - *reinterpret_cast<uint32_t*>(pDestPixel) = FXARGB_TODIB(argb); - } else { - *pDestPixel++ = FXARGB_B(argb); - *pDestPixel++ = FXARGB_G(argb); - *pDestPixel = FXARGB_R(argb); - } - } +size_t CPDF_DIB::GetEstimatedImageMemoryBurden() const { + return m_pCachedBitmap ? m_pCachedBitmap->GetEstimatedImageMemoryBurden() : 0; } bool CPDF_DIB::TransMask() const { - return m_bLoadMask && m_GroupFamily == PDFCS_DEVICECMYK && - m_Family == PDFCS_DEVICECMYK; + return m_bLoadMask && m_GroupFamily == CPDF_ColorSpace::Family::kDeviceCMYK && + m_Family == CPDF_ColorSpace::Family::kDeviceCMYK; } void CPDF_DIB::SetMaskProperties() { - m_bpp = 1; m_bpc = 1; m_nComponents = 1; - m_AlphaFlag = 1; + m_Format = FXDIB_Format::k1bppMask; +} + +uint32_t CPDF_DIB::Get1BitSetValue() const { + if (m_CompData[0].m_ColorKeyMax == 1) + return 0x00000000; + return HasPalette() ? GetPaletteSpan()[1] : 0xFFFFFFFF; +} + +uint32_t CPDF_DIB::Get1BitResetValue() const { + if (m_CompData[0].m_ColorKeyMin == 0) + return 0x00000000; + return HasPalette() ? GetPaletteSpan()[0] : 0xFF000000; }
diff --git a/core/fpdfapi/page/cpdf_dib.h b/core/fpdfapi/page/cpdf_dib.h index 6960cea..a24d192 100644 --- a/core/fpdfapi/page/cpdf_dib.h +++ b/core/fpdfapi/page/cpdf_dib.h
@@ -1,4 +1,4 @@ -// Copyright 2017 PDFium Authors. All rights reserved. +// Copyright 2017 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -7,13 +7,13 @@ #ifndef CORE_FPDFAPI_PAGE_CPDF_DIB_H_ #define CORE_FPDFAPI_PAGE_CPDF_DIB_H_ +#include <stdint.h> + #include <memory> #include <vector> -#include "core/fpdfapi/page/cpdf_clippath.h" #include "core/fpdfapi/page/cpdf_colorspace.h" -#include "core/fpdfapi/page/cpdf_graphicstates.h" -#include "core/fxcrt/fx_memory_wrappers.h" +#include "core/fxcrt/data_vector.h" #include "core/fxcrt/retain_ptr.h" #include "core/fxcrt/unowned_ptr.h" #include "core/fxge/dib/cfx_dibbase.h" @@ -42,100 +42,79 @@ public: enum class LoadState : uint8_t { kFail, kSuccess, kContinue }; - template <typename T, typename... Args> - friend RetainPtr<T> pdfium::MakeRetain(Args&&... args); - - bool Load(CPDF_Document* pDoc, const CPDF_Stream* pStream); + CONSTRUCT_VIA_MAKE_RETAIN; // CFX_DIBBase: + pdfium::span<uint8_t> GetBuffer() const override; + pdfium::span<const uint8_t> GetScanline(int line) const override; bool SkipToScanline(int line, PauseIndicatorIface* pPause) const override; - uint8_t* GetBuffer() const override; - const uint8_t* GetScanline(int line) const override; - void DownSampleScanline(int line, - uint8_t* dest_scan, - int dest_bpp, - int dest_width, - bool bFlipX, - int clip_left, - int clip_width) const override; + size_t GetEstimatedImageMemoryBurden() const override; RetainPtr<CPDF_ColorSpace> GetColorSpace() const { return m_pColorSpace; } uint32_t GetMatteColor() const { return m_MatteColor; } + bool IsJBigImage() const; - LoadState StartLoadDIBBase(CPDF_Document* pDoc, - const CPDF_Stream* pStream, - bool bHasMask, + bool Load(); + LoadState StartLoadDIBBase(bool bHasMask, const CPDF_Dictionary* pFormResources, - CPDF_Dictionary* pPageResources, + const CPDF_Dictionary* pPageResources, bool bStdCS, - uint32_t GroupFamily, - bool bLoadMask); + CPDF_ColorSpace::Family GroupFamily, + bool bLoadMask, + const CFX_Size& max_size_required); LoadState ContinueLoadDIBBase(PauseIndicatorIface* pPause); RetainPtr<CPDF_DIB> DetachMask(); - bool IsJBigImage() const; - private: - CPDF_DIB(); + CPDF_DIB(CPDF_Document* pDoc, RetainPtr<const CPDF_Stream> pStream); ~CPDF_DIB() override; + struct JpxSMaskInlineData { + JpxSMaskInlineData(); + ~JpxSMaskInlineData(); + + int width = 0; + int height = 0; + DataVector<uint8_t> data; + }; + + bool LoadInternal(const CPDF_Dictionary* pFormResources, + const CPDF_Dictionary* pPageResources); + bool ContinueInternal(); LoadState StartLoadMask(); - LoadState StartLoadMaskDIB(RetainPtr<const CPDF_Stream> mask); + LoadState StartLoadMaskDIB(RetainPtr<const CPDF_Stream> mask_stream); bool ContinueToLoadMask(); LoadState ContinueLoadMaskDIB(PauseIndicatorIface* pPause); bool LoadColorInfo(const CPDF_Dictionary* pFormResources, const CPDF_Dictionary* pPageResources); - bool GetDecodeAndMaskArray(bool* bDefaultDecode, bool* bColorKey); - RetainPtr<CFX_DIBitmap> LoadJpxBitmap(); + bool GetDecodeAndMaskArray(); + RetainPtr<CFX_DIBitmap> LoadJpxBitmap(uint8_t resolution_levels_to_skip); void LoadPalette(); - LoadState CreateDecoder(); + LoadState CreateDecoder(uint8_t resolution_levels_to_skip); bool CreateDCTDecoder(pdfium::span<const uint8_t> src_span, const CPDF_Dictionary* pParams); - void TranslateScanline24bpp(uint8_t* dest_scan, - const uint8_t* src_scan) const; - bool TranslateScanline24bppDefaultDecode(uint8_t* dest_scan, - const uint8_t* src_scan) const; - void ValidateDictParam(); - void DownSampleScanline1Bit(int orig_Bpp, - int dest_Bpp, - uint32_t src_width, - const uint8_t* pSrcLine, - uint8_t* dest_scan, - int dest_width, - bool bFlipX, - int clip_left, - int clip_width) const; - void DownSampleScanline8Bit(int orig_Bpp, - int dest_Bpp, - uint32_t src_width, - const uint8_t* pSrcLine, - uint8_t* dest_scan, - int dest_width, - bool bFlipX, - int clip_left, - int clip_width) const; - void DownSampleScanline32Bit(int orig_Bpp, - int dest_Bpp, - uint32_t src_width, - const uint8_t* pSrcLine, - uint8_t* dest_scan, - int dest_width, - bool bFlipX, - int clip_left, - int clip_width) const; + void TranslateScanline24bpp(pdfium::span<uint8_t> dest_scan, + pdfium::span<const uint8_t> src_scan) const; + bool TranslateScanline24bppDefaultDecode( + pdfium::span<uint8_t> dest_scan, + pdfium::span<const uint8_t> src_scan) const; + bool ValidateDictParam(const ByteString& filter); bool TransMask() const; void SetMaskProperties(); - UnownedPtr<CPDF_Document> m_pDocument; - RetainPtr<const CPDF_Stream> m_pStream; + uint32_t Get1BitSetValue() const; + uint32_t Get1BitResetValue() const; + + UnownedPtr<CPDF_Document> const m_pDocument; + RetainPtr<const CPDF_Stream> const m_pStream; RetainPtr<const CPDF_Dictionary> m_pDict; RetainPtr<CPDF_StreamAcc> m_pStreamAcc; RetainPtr<CPDF_ColorSpace> m_pColorSpace; - uint32_t m_Family = 0; uint32_t m_bpc = 0; uint32_t m_bpc_orig = 0; uint32_t m_nComponents = 0; - uint32_t m_GroupFamily = 0; + CPDF_ColorSpace::Family m_Family = CPDF_ColorSpace::Family::kUnknown; + CPDF_ColorSpace::Family m_GroupFamily = CPDF_ColorSpace::Family::kUnknown; uint32_t m_MatteColor = 0; LoadState m_Status = LoadState::kFail; bool m_bLoadMask = false; @@ -146,13 +125,14 @@ bool m_bHasMask = false; bool m_bStdCS = false; std::vector<DIB_COMP_DATA> m_CompData; - std::unique_ptr<uint8_t, FxFreeDeleter> m_pLineBuf; - std::unique_ptr<uint8_t, FxFreeDeleter> m_pMaskedLine; + mutable DataVector<uint8_t> m_LineBuf; + mutable DataVector<uint8_t> m_MaskBuf; RetainPtr<CFX_DIBitmap> m_pCachedBitmap; // Note: Must not create a cycle between CPDF_DIB instances. RetainPtr<CPDF_DIB> m_pMask; RetainPtr<CPDF_StreamAcc> m_pGlobalAcc; std::unique_ptr<fxcodec::ScanlineDecoder> m_pDecoder; + JpxSMaskInlineData m_JpxInlineData; // Must come after |m_pCachedBitmap|. std::unique_ptr<fxcodec::Jbig2Context> m_pJbig2Context;
diff --git a/core/fpdfapi/page/cpdf_docpagedata.cpp b/core/fpdfapi/page/cpdf_docpagedata.cpp index 9c8bc92..b00a616 100644 --- a/core/fpdfapi/page/cpdf_docpagedata.cpp +++ b/core/fpdfapi/page/cpdf_docpagedata.cpp
@@ -1,4 +1,4 @@ -// Copyright 2014 PDFium Authors. All rights reserved. +// Copyright 2014 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -13,6 +13,7 @@ #include <vector> #include "build/build_config.h" +#include "constants/font_encodings.h" #include "core/fpdfapi/font/cpdf_type1font.h" #include "core/fpdfapi/page/cpdf_form.h" #include "core/fpdfapi/page/cpdf_iccprofile.h" @@ -30,14 +31,16 @@ #include "core/fpdfapi/parser/cpdf_stream_acc.h" #include "core/fpdfapi/parser/cpdf_string.h" #include "core/fxcrt/fx_codepage.h" +#include "core/fxcrt/fx_memory.h" #include "core/fxcrt/fx_safe_types.h" +#include "core/fxcrt/scoped_set_insertion.h" #include "core/fxge/cfx_font.h" #include "core/fxge/cfx_fontmapper.h" #include "core/fxge/cfx_substfont.h" #include "core/fxge/cfx_unicodeencoding.h" #include "core/fxge/fx_font.h" -#include "third_party/base/ptr_util.h" -#include "third_party/base/stl_util.h" +#include "third_party/base/check.h" +#include "third_party/base/containers/contains.h" namespace { @@ -49,17 +52,17 @@ } if (i == widths.size()) { int first = pWidthArray->GetIntegerAt(pWidthArray->size() - 1); - pWidthArray->AddNew<CPDF_Number>(first + static_cast<int>(widths.size()) - - 1); - pWidthArray->AddNew<CPDF_Number>(widths[0]); + pWidthArray->AppendNew<CPDF_Number>(first + + static_cast<int>(widths.size()) - 1); + pWidthArray->AppendNew<CPDF_Number>(widths[0]); return; } - CPDF_Array* pWidthArray1 = pWidthArray->AddNew<CPDF_Array>(); + auto pWidthArray1 = pWidthArray->AppendNew<CPDF_Array>(); for (int w : widths) - pWidthArray1->AddNew<CPDF_Number>(w); + pWidthArray1->AppendNew<CPDF_Number>(w); } -#if defined(OS_WIN) +#if BUILDFLAG(IS_WIN) void InsertWidthArray(HDC hDC, int start, int end, CPDF_Array* pWidthArray) { std::vector<int> widths(end - start + 1); GetCharWidth(hDC, start, end, widths.data()); @@ -77,7 +80,7 @@ } return result; } -#endif // defined(OS_WIN) +#endif // BUILDFLAG(IS_WIN) void InsertWidthArray1(CFX_Font* pFont, CFX_UnicodeEncoding* pEncoding, @@ -116,7 +119,7 @@ return flags; } -void ProcessNonbCJK(CPDF_Dictionary* pBaseDict, +void ProcessNonbCJK(RetainPtr<CPDF_Dictionary> pBaseDict, bool bold, bool italic, ByteString basefont, @@ -174,7 +177,8 @@ CPDF_PageModule::GetInstance()->ClearStockFont(GetDocument()); } -RetainPtr<CPDF_Font> CPDF_DocPageData::GetFont(CPDF_Dictionary* pFontDict) { +RetainPtr<CPDF_Font> CPDF_DocPageData::GetFont( + RetainPtr<CPDF_Dictionary> pFontDict) { if (!pFontDict) return nullptr; @@ -187,7 +191,7 @@ if (!pFont) return nullptr; - m_FontMap[pFontDict].Reset(pFont.Get()); + m_FontMap[std::move(pFontDict)].Reset(pFont.Get()); return pFont; } @@ -217,7 +221,7 @@ return pdfium::WrapRetain(pFont); } - CPDF_Dictionary* pDict = GetDocument()->NewIndirect<CPDF_Dictionary>(); + auto pDict = GetDocument()->NewIndirect<CPDF_Dictionary>(); pDict->SetNewFor<CPDF_Name>("Type", "Font"); pDict->SetNewFor<CPDF_Name>("Subtype", "Type1"); pDict->SetNewFor<CPDF_Name>("BaseFont", fontName); @@ -231,7 +235,7 @@ if (!pFont) return nullptr; - m_FontMap[pDict].Reset(pFont.Get()); + m_FontMap[std::move(pDict)].Reset(pFont.Get()); return pFont; } @@ -258,73 +262,76 @@ if (!pCSObj) return nullptr; - if (pdfium::ContainsKey(*pVisitedInternal, pCSObj)) + if (pdfium::Contains(*pVisitedInternal, pCSObj)) return nullptr; - pdfium::ScopedSetInsertion<const CPDF_Object*> insertion(pVisitedInternal, - pCSObj); + ScopedSetInsertion<const CPDF_Object*> insertion(pVisitedInternal, pCSObj); if (pCSObj->IsName()) { ByteString name = pCSObj->GetString(); - RetainPtr<CPDF_ColorSpace> pCS = CPDF_ColorSpace::ColorspaceFromName(name); + RetainPtr<CPDF_ColorSpace> pCS = CPDF_ColorSpace::GetStockCSForName(name); if (!pCS && pResources) { - const CPDF_Dictionary* pList = pResources->GetDictFor("ColorSpace"); + RetainPtr<const CPDF_Dictionary> pList = + pResources->GetDictFor("ColorSpace"); if (pList) { - return GetColorSpaceInternal(pList->GetDirectObjectFor(name), nullptr, - pVisited, pVisitedInternal); + return GetColorSpaceInternal(pList->GetDirectObjectFor(name).Get(), + nullptr, pVisited, pVisitedInternal); } } if (!pCS || !pResources) return pCS; - const CPDF_Dictionary* pColorSpaces = pResources->GetDictFor("ColorSpace"); + RetainPtr<const CPDF_Dictionary> pColorSpaces = + pResources->GetDictFor("ColorSpace"); if (!pColorSpaces) return pCS; - const CPDF_Object* pDefaultCS = nullptr; + RetainPtr<const CPDF_Object> pDefaultCS; switch (pCS->GetFamily()) { - case PDFCS_DEVICERGB: + case CPDF_ColorSpace::Family::kDeviceRGB: pDefaultCS = pColorSpaces->GetDirectObjectFor("DefaultRGB"); break; - case PDFCS_DEVICEGRAY: + case CPDF_ColorSpace::Family::kDeviceGray: pDefaultCS = pColorSpaces->GetDirectObjectFor("DefaultGray"); break; - case PDFCS_DEVICECMYK: + case CPDF_ColorSpace::Family::kDeviceCMYK: pDefaultCS = pColorSpaces->GetDirectObjectFor("DefaultCMYK"); break; + default: + break; } if (!pDefaultCS) return pCS; - return GetColorSpaceInternal(pDefaultCS, nullptr, pVisited, + return GetColorSpaceInternal(pDefaultCS.Get(), nullptr, pVisited, pVisitedInternal); } - const CPDF_Array* pArray = pCSObj->AsArray(); + RetainPtr<const CPDF_Array> pArray(pCSObj->AsArray()); if (!pArray || pArray->IsEmpty()) return nullptr; if (pArray->size() == 1) { - return GetColorSpaceInternal(pArray->GetDirectObjectAt(0), pResources, + return GetColorSpaceInternal(pArray->GetDirectObjectAt(0).Get(), pResources, pVisited, pVisitedInternal); } - auto it = m_ColorSpaceMap.find(pCSObj); + auto it = m_ColorSpaceMap.find(pArray); if (it != m_ColorSpaceMap.end() && it->second) return pdfium::WrapRetain(it->second.Get()); RetainPtr<CPDF_ColorSpace> pCS = - CPDF_ColorSpace::Load(GetDocument(), pArray, pVisited); + CPDF_ColorSpace::Load(GetDocument(), pArray.Get(), pVisited); if (!pCS) return nullptr; - m_ColorSpaceMap[pCSObj].Reset(pCS.Get()); + m_ColorSpaceMap[std::move(pArray)].Reset(pCS.Get()); return pCS; } -RetainPtr<CPDF_Pattern> CPDF_DocPageData::GetPattern(CPDF_Object* pPatternObj, - bool bShading, - const CFX_Matrix& matrix) { +RetainPtr<CPDF_Pattern> CPDF_DocPageData::GetPattern( + RetainPtr<CPDF_Object> pPatternObj, + const CFX_Matrix& matrix) { if (!pPatternObj) return nullptr; @@ -332,33 +339,43 @@ if (it != m_PatternMap.end() && it->second) return pdfium::WrapRetain(it->second.Get()); + RetainPtr<const CPDF_Dictionary> pDict = pPatternObj->GetDict(); + if (!pDict) + return nullptr; + RetainPtr<CPDF_Pattern> pPattern; - if (bShading) { + int type = pDict->GetIntegerFor("PatternType"); + if (type == CPDF_Pattern::kTiling) { + pPattern = pdfium::MakeRetain<CPDF_TilingPattern>(GetDocument(), + pPatternObj, matrix); + } else if (type == CPDF_Pattern::kShading) { pPattern = pdfium::MakeRetain<CPDF_ShadingPattern>( - GetDocument(), pPatternObj, true, matrix); + GetDocument(), pPatternObj, false, matrix); } else { - CPDF_Dictionary* pDict = pPatternObj->GetDict(); - if (!pDict) - return nullptr; - - int type = pDict->GetIntegerFor("PatternType"); - if (type == CPDF_Pattern::kTiling) { - pPattern = pdfium::MakeRetain<CPDF_TilingPattern>(GetDocument(), - pPatternObj, matrix); - } else if (type == CPDF_Pattern::kShading) { - pPattern = pdfium::MakeRetain<CPDF_ShadingPattern>( - GetDocument(), pPatternObj, false, matrix); - } else { - return nullptr; - } + return nullptr; } + m_PatternMap[pPatternObj].Reset(pPattern.Get()); + return pPattern; +} +RetainPtr<CPDF_ShadingPattern> CPDF_DocPageData::GetShading( + RetainPtr<CPDF_Object> pPatternObj, + const CFX_Matrix& matrix) { + if (!pPatternObj) + return nullptr; + + auto it = m_PatternMap.find(pPatternObj); + if (it != m_PatternMap.end() && it->second) + return pdfium::WrapRetain(it->second->AsShadingPattern()); + + auto pPattern = pdfium::MakeRetain<CPDF_ShadingPattern>( + GetDocument(), pPatternObj, true, matrix); m_PatternMap[pPatternObj].Reset(pPattern.Get()); return pPattern; } RetainPtr<CPDF_Image> CPDF_DocPageData::GetImage(uint32_t dwStreamObjNum) { - ASSERT(dwStreamObjNum); + DCHECK(dwStreamObjNum); auto it = m_ImageMap.find(dwStreamObjNum); if (it != m_ImageMap.end()) return it->second; @@ -369,14 +386,14 @@ } void CPDF_DocPageData::MaybePurgeImage(uint32_t dwStreamObjNum) { - ASSERT(dwStreamObjNum); + DCHECK(dwStreamObjNum); auto it = m_ImageMap.find(dwStreamObjNum); if (it != m_ImageMap.end() && it->second->HasOneRef()) m_ImageMap.erase(it); } RetainPtr<CPDF_IccProfile> CPDF_DocPageData::GetIccProfile( - const CPDF_Stream* pProfileStream) { + RetainPtr<const CPDF_Stream> pProfileStream) { if (!pProfileStream) return nullptr; @@ -390,25 +407,25 @@ ByteString bsDigest = pAccessor->ComputeDigest(); auto hash_it = m_HashProfileMap.find(bsDigest); if (hash_it != m_HashProfileMap.end()) { - auto it_copied_stream = m_IccProfileMap.find(hash_it->second.Get()); + auto it_copied_stream = m_IccProfileMap.find(hash_it->second); if (it_copied_stream != m_IccProfileMap.end() && it_copied_stream->second) return pdfium::WrapRetain(it_copied_stream->second.Get()); } auto pProfile = pdfium::MakeRetain<CPDF_IccProfile>(pProfileStream, pAccessor->GetSpan()); m_IccProfileMap[pProfileStream].Reset(pProfile.Get()); - m_HashProfileMap[bsDigest].Reset(pProfileStream); + m_HashProfileMap[bsDigest] = std::move(pProfileStream); return pProfile; } RetainPtr<CPDF_StreamAcc> CPDF_DocPageData::GetFontFileStreamAcc( - const CPDF_Stream* pFontStream) { - ASSERT(pFontStream); + RetainPtr<const CPDF_Stream> pFontStream) { + DCHECK(pFontStream); auto it = m_FontFileMap.find(pFontStream); if (it != m_FontFileMap.end()) return it->second; - const CPDF_Dictionary* pFontDict = pFontStream->GetDict(); + RetainPtr<const CPDF_Dictionary> pFontDict = pFontStream->GetDict(); int32_t len1 = pFontDict->GetIntegerFor("Length1"); int32_t len2 = pFontDict->GetIntegerFor("Length2"); int32_t len3 = pFontDict->GetIntegerFor("Length3"); @@ -422,38 +439,46 @@ auto pFontAcc = pdfium::MakeRetain<CPDF_StreamAcc>(pFontStream); pFontAcc->LoadAllDataFilteredWithEstimatedSize(org_size); - m_FontFileMap[pFontStream] = pFontAcc; + m_FontFileMap[std::move(pFontStream)] = pFontAcc; return pFontAcc; } void CPDF_DocPageData::MaybePurgeFontFileStreamAcc( - const CPDF_Stream* pFontStream) { + RetainPtr<CPDF_StreamAcc>&& pStreamAcc) { + if (!pStreamAcc) + return; + + RetainPtr<const CPDF_Stream> pFontStream = pStreamAcc->GetStream(); if (!pFontStream) return; - auto it = m_FontFileMap.find(pFontStream); + pStreamAcc.Reset(); // Drop moved caller's reference. + auto it = m_FontFileMap.find(std::move(pFontStream)); if (it != m_FontFileMap.end() && it->second->HasOneRef()) m_FontFileMap.erase(it); } std::unique_ptr<CPDF_Font::FormIface> CPDF_DocPageData::CreateForm( CPDF_Document* pDocument, - CPDF_Dictionary* pPageResources, - CPDF_Stream* pFormStream) { - return pdfium::MakeUnique<CPDF_Form>(pDocument, pPageResources, pFormStream); + RetainPtr<CPDF_Dictionary> pPageResources, + RetainPtr<CPDF_Stream> pFormStream) { + return std::make_unique<CPDF_Form>(pDocument, std::move(pPageResources), + std::move(pFormStream)); } RetainPtr<CPDF_Font> CPDF_DocPageData::AddStandardFont( const ByteString& fontName, const CPDF_FontEncoding* pEncoding) { ByteString mutable_name(fontName); - if (!CFX_FontMapper::GetStandardFontName(&mutable_name)) + absl::optional<CFX_FontMapper::StandardFont> font_id = + CFX_FontMapper::GetStandardFontName(&mutable_name); + if (!font_id.has_value()) return nullptr; return GetStandardFont(mutable_name, pEncoding); } RetainPtr<CPDF_Font> CPDF_DocPageData::AddFont(std::unique_ptr<CFX_Font> pFont, - int charset) { + FX_Charset charset) { if (!pFont) return nullptr; @@ -462,35 +487,37 @@ basefont.Replace(" ", ""); int flags = CalculateFlags(pFont->IsBold(), pFont->IsItalic(), pFont->IsFixedWidth(), - false, false, charset == FX_CHARSET_Symbol); + false, false, charset == FX_Charset::kSymbol); - CPDF_Dictionary* pBaseDict = GetDocument()->NewIndirect<CPDF_Dictionary>(); + auto pBaseDict = GetDocument()->NewIndirect<CPDF_Dictionary>(); pBaseDict->SetNewFor<CPDF_Name>("Type", "Font"); - auto pEncoding = pdfium::MakeUnique<CFX_UnicodeEncoding>(pFont.get()); - CPDF_Dictionary* pFontDict = pBaseDict; + + auto pEncoding = std::make_unique<CFX_UnicodeEncoding>(pFont.get()); + RetainPtr<CPDF_Dictionary> pFontDict = pBaseDict; if (!bCJK) { auto pWidths = pdfium::MakeRetain<CPDF_Array>(); for (int charcode = 32; charcode < 128; charcode++) { int glyph_index = pEncoding->GlyphFromCharCode(charcode); int char_width = pFont->GetGlyphWidth(glyph_index); - pWidths->AddNew<CPDF_Number>(char_width); + pWidths->AppendNew<CPDF_Number>(char_width); } - if (charset == FX_CHARSET_ANSI || charset == FX_CHARSET_Default || - charset == FX_CHARSET_Symbol) { - pBaseDict->SetNewFor<CPDF_Name>("Encoding", "WinAnsiEncoding"); + if (charset == FX_Charset::kANSI || charset == FX_Charset::kDefault || + charset == FX_Charset::kSymbol) { + pBaseDict->SetNewFor<CPDF_Name>("Encoding", + pdfium::font_encodings::kWinAnsiEncoding); for (int charcode = 128; charcode <= 255; charcode++) { int glyph_index = pEncoding->GlyphFromCharCode(charcode); int char_width = pFont->GetGlyphWidth(glyph_index); - pWidths->AddNew<CPDF_Number>(char_width); + pWidths->AppendNew<CPDF_Number>(char_width); } } else { - size_t i = CalculateEncodingDict(charset, pBaseDict); - if (i < FX_ArraySize(g_FX_CharsetUnicodes)) { - const uint16_t* pUnicodes = g_FX_CharsetUnicodes[i].m_pUnicodes; + size_t i = CalculateEncodingDict(charset, pBaseDict.Get()); + if (i < std::size(kFX_CharsetUnicodes)) { + const uint16_t* pUnicodes = kFX_CharsetUnicodes[i].m_pUnicodes; for (int j = 0; j < 128; j++) { int glyph_index = pEncoding->GlyphFromCharCode(pUnicodes[j]); int char_width = pFont->GetGlyphWidth(glyph_index); - pWidths->AddNew<CPDF_Number>(char_width); + pWidths->AppendNew<CPDF_Number>(char_width); } } } @@ -504,19 +531,18 @@ }); } int italicangle = pFont->GetSubstFontItalicAngle(); - FX_RECT bbox; - pFont->GetBBox(&bbox); + FX_RECT bbox = pFont->GetBBox().value_or(FX_RECT()); auto pBBox = pdfium::MakeRetain<CPDF_Array>(); - pBBox->AddNew<CPDF_Number>(bbox.left); - pBBox->AddNew<CPDF_Number>(bbox.bottom); - pBBox->AddNew<CPDF_Number>(bbox.right); - pBBox->AddNew<CPDF_Number>(bbox.top); + pBBox->AppendNew<CPDF_Number>(bbox.left); + pBBox->AppendNew<CPDF_Number>(bbox.bottom); + pBBox->AppendNew<CPDF_Number>(bbox.right); + pBBox->AppendNew<CPDF_Number>(bbox.top); int32_t nStemV = 0; if (pFont->GetSubstFont()) { nStemV = pFont->GetSubstFont()->m_Weight / 5; } else { static const char stem_chars[] = {'i', 'I', '!', '1'}; - const size_t count = FX_ArraySize(stem_chars); + const size_t count = std::size(stem_chars); uint32_t glyph = pEncoding->GlyphFromCharCode(stem_chars[0]); nStemV = pFont->GetGlyphWidth(glyph); for (size_t i = 1; i < count; i++) { @@ -526,16 +552,16 @@ nStemV = width; } } - CPDF_Dictionary* pFontDesc = - ToDictionary(GetDocument()->AddIndirectObject(CalculateFontDesc( - GetDocument(), basefont, flags, italicangle, pFont->GetAscent(), - pFont->GetDescent(), std::move(pBBox), nStemV))); + RetainPtr<CPDF_Dictionary> pFontDesc = CalculateFontDesc( + GetDocument(), basefont, flags, italicangle, pFont->GetAscent(), + pFont->GetDescent(), std::move(pBBox), nStemV); + uint32_t new_objnum = GetDocument()->AddIndirectObject(std::move(pFontDesc)); pFontDict->SetNewFor<CPDF_Reference>("FontDescriptor", GetDocument(), - pFontDesc->GetObjNum()); + new_objnum); return GetFont(pBaseDict); } -#if defined(OS_WIN) +#if BUILDFLAG(IS_WIN) RetainPtr<CPDF_Font> CPDF_DocPageData::AddWindowsFont(LOGFONTA* pLogFont) { pLogFont->lfHeight = -1000; pLogFont->lfWidth = 0; @@ -553,13 +579,15 @@ LPBYTE tm_buf = FX_Alloc(BYTE, tm_size); OUTLINETEXTMETRIC* ptm = reinterpret_cast<OUTLINETEXTMETRIC*>(tm_buf); GetOutlineTextMetrics(hDC, tm_size, ptm); - int flags = CalculateFlags(false, pLogFont->lfItalic != 0, - (pLogFont->lfPitchAndFamily & 3) == FIXED_PITCH, - (pLogFont->lfPitchAndFamily & 0xf8) == FF_ROMAN, - (pLogFont->lfPitchAndFamily & 0xf8) == FF_SCRIPT, - pLogFont->lfCharSet == FX_CHARSET_Symbol); + int flags = CalculateFlags( + false, pLogFont->lfItalic != 0, + (pLogFont->lfPitchAndFamily & 3) == FIXED_PITCH, + (pLogFont->lfPitchAndFamily & 0xf8) == FF_ROMAN, + (pLogFont->lfPitchAndFamily & 0xf8) == FF_SCRIPT, + pLogFont->lfCharSet == static_cast<int>(FX_Charset::kSymbol)); - const bool bCJK = FX_CharSetIsCJK(pLogFont->lfCharSet); + const FX_Charset eCharset = FX_GetCharsetFromInt(pLogFont->lfCharSet); + const bool bCJK = FX_CharSetIsCJK(eCharset); ByteString basefont; if (bCJK) basefont = GetPSNameFromTT(hDC); @@ -575,122 +603,122 @@ ptm->otmrcFontBox.right, ptm->otmrcFontBox.top}; FX_Free(tm_buf); basefont.Replace(" ", ""); - CPDF_Dictionary* pBaseDict = GetDocument()->NewIndirect<CPDF_Dictionary>(); + auto pBaseDict = GetDocument()->NewIndirect<CPDF_Dictionary>(); pBaseDict->SetNewFor<CPDF_Name>("Type", "Font"); - CPDF_Dictionary* pFontDict = pBaseDict; + RetainPtr<CPDF_Dictionary> pFontDict = pBaseDict; if (!bCJK) { - if (pLogFont->lfCharSet == FX_CHARSET_ANSI || - pLogFont->lfCharSet == FX_CHARSET_Default || - pLogFont->lfCharSet == FX_CHARSET_Symbol) { - pBaseDict->SetNewFor<CPDF_Name>("Encoding", "WinAnsiEncoding"); + if (eCharset == FX_Charset::kANSI || eCharset == FX_Charset::kDefault || + eCharset == FX_Charset::kSymbol) { + pBaseDict->SetNewFor<CPDF_Name>("Encoding", + pdfium::font_encodings::kWinAnsiEncoding); } else { - CalculateEncodingDict(pLogFont->lfCharSet, pBaseDict); + CalculateEncodingDict(eCharset, pBaseDict.Get()); } int char_widths[224]; GetCharWidth(hDC, 32, 255, char_widths); auto pWidths = pdfium::MakeRetain<CPDF_Array>(); for (size_t i = 0; i < 224; i++) - pWidths->AddNew<CPDF_Number>(char_widths[i]); + pWidths->AppendNew<CPDF_Number>(char_widths[i]); ProcessNonbCJK(pBaseDict, pLogFont->lfWeight > FW_MEDIUM, pLogFont->lfItalic != 0, basefont, std::move(pWidths)); } else { pFontDict = - ProcessbCJK(pBaseDict, pLogFont->lfCharSet, basefont, + ProcessbCJK(pBaseDict, eCharset, basefont, [&hDC](wchar_t start, wchar_t end, CPDF_Array* widthArr) { InsertWidthArray(hDC, start, end, widthArr); }); } auto pBBox = pdfium::MakeRetain<CPDF_Array>(); for (int i = 0; i < 4; i++) - pBBox->AddNew<CPDF_Number>(bbox[i]); + pBBox->AppendNew<CPDF_Number>(bbox[i]); RetainPtr<CPDF_Dictionary> pFontDesc = CalculateFontDesc(GetDocument(), basefont, flags, italicangle, ascend, descend, std::move(pBBox), pLogFont->lfWeight / 5); pFontDesc->SetNewFor<CPDF_Number>("CapHeight", capheight); - pFontDict->SetFor("FontDescriptor", - GetDocument() - ->AddIndirectObject(std::move(pFontDesc)) - ->MakeReference(GetDocument())); + GetDocument()->AddIndirectObject(pFontDesc); + pFontDict->SetFor("FontDescriptor", pFontDesc->MakeReference(GetDocument())); hFont = SelectObject(hDC, hFont); DeleteObject(hFont); DeleteDC(hDC); - return GetFont(pBaseDict); + return GetFont(std::move(pBaseDict)); } -#endif // defined(OS_WIN) +#endif // BUILDFLAG(IS_WIN) -size_t CPDF_DocPageData::CalculateEncodingDict(int charset, +size_t CPDF_DocPageData::CalculateEncodingDict(FX_Charset charset, CPDF_Dictionary* pBaseDict) { size_t i; - for (i = 0; i < FX_ArraySize(g_FX_CharsetUnicodes); ++i) { - if (g_FX_CharsetUnicodes[i].m_Charset == charset) + for (i = 0; i < std::size(kFX_CharsetUnicodes); ++i) { + if (kFX_CharsetUnicodes[i].m_Charset == charset) break; } - if (i == FX_ArraySize(g_FX_CharsetUnicodes)) + if (i == std::size(kFX_CharsetUnicodes)) return i; - CPDF_Dictionary* pEncodingDict = - GetDocument()->NewIndirect<CPDF_Dictionary>(); - pEncodingDict->SetNewFor<CPDF_Name>("BaseEncoding", "WinAnsiEncoding"); + auto pEncodingDict = GetDocument()->NewIndirect<CPDF_Dictionary>(); + pEncodingDict->SetNewFor<CPDF_Name>("BaseEncoding", + pdfium::font_encodings::kWinAnsiEncoding); - CPDF_Array* pArray = pEncodingDict->SetNewFor<CPDF_Array>("Differences"); - pArray->AddNew<CPDF_Number>(128); + auto pArray = pEncodingDict->SetNewFor<CPDF_Array>("Differences"); + pArray->AppendNew<CPDF_Number>(128); - const uint16_t* pUnicodes = g_FX_CharsetUnicodes[i].m_pUnicodes; + const uint16_t* pUnicodes = kFX_CharsetUnicodes[i].m_pUnicodes; for (int j = 0; j < 128; j++) { - ByteString name = PDF_AdobeNameFromUnicode(pUnicodes[j]); - pArray->AddNew<CPDF_Name>(name.IsEmpty() ? ".notdef" : name); + ByteString name = AdobeNameFromUnicode(pUnicodes[j]); + pArray->AppendNew<CPDF_Name>(name.IsEmpty() ? ".notdef" : name); } pBaseDict->SetNewFor<CPDF_Reference>("Encoding", GetDocument(), pEncodingDict->GetObjNum()); return i; } -CPDF_Dictionary* CPDF_DocPageData::ProcessbCJK( - CPDF_Dictionary* pBaseDict, - int charset, +RetainPtr<CPDF_Dictionary> CPDF_DocPageData::ProcessbCJK( + RetainPtr<CPDF_Dictionary> pBaseDict, + FX_Charset charset, ByteString basefont, std::function<void(wchar_t, wchar_t, CPDF_Array*)> Insert) { - CPDF_Dictionary* pFontDict = GetDocument()->NewIndirect<CPDF_Dictionary>(); + auto pFontDict = GetDocument()->NewIndirect<CPDF_Dictionary>(); ByteString cmap; ByteString ordering; int supplement = 0; - CPDF_Array* pWidthArray = pFontDict->SetNewFor<CPDF_Array>("W"); + auto pWidthArray = pFontDict->SetNewFor<CPDF_Array>("W"); switch (charset) { - case FX_CHARSET_ChineseTraditional: + case FX_Charset::kChineseTraditional: cmap = "ETenms-B5-H"; ordering = "CNS1"; supplement = 4; - pWidthArray->AddNew<CPDF_Number>(1); - Insert(0x20, 0x7e, pWidthArray); + pWidthArray->AppendNew<CPDF_Number>(1); + Insert(0x20, 0x7e, pWidthArray.Get()); break; - case FX_CHARSET_ChineseSimplified: + case FX_Charset::kChineseSimplified: cmap = "GBK-EUC-H"; ordering = "GB1"; supplement = 2; - pWidthArray->AddNew<CPDF_Number>(7716); - Insert(0x20, 0x20, pWidthArray); - pWidthArray->AddNew<CPDF_Number>(814); - Insert(0x21, 0x7e, pWidthArray); + pWidthArray->AppendNew<CPDF_Number>(7716); + Insert(0x20, 0x20, pWidthArray.Get()); + pWidthArray->AppendNew<CPDF_Number>(814); + Insert(0x21, 0x7e, pWidthArray.Get()); break; - case FX_CHARSET_Hangul: + case FX_Charset::kHangul: cmap = "KSCms-UHC-H"; ordering = "Korea1"; supplement = 2; - pWidthArray->AddNew<CPDF_Number>(1); - Insert(0x20, 0x7e, pWidthArray); + pWidthArray->AppendNew<CPDF_Number>(1); + Insert(0x20, 0x7e, pWidthArray.Get()); break; - case FX_CHARSET_ShiftJIS: + case FX_Charset::kShiftJIS: cmap = "90ms-RKSJ-H"; ordering = "Japan1"; supplement = 5; - pWidthArray->AddNew<CPDF_Number>(231); - Insert(0x20, 0x7d, pWidthArray); - pWidthArray->AddNew<CPDF_Number>(326); - Insert(0xa0, 0xa0, pWidthArray); - pWidthArray->AddNew<CPDF_Number>(327); - Insert(0xa1, 0xdf, pWidthArray); - pWidthArray->AddNew<CPDF_Number>(631); - Insert(0x7e, 0x7e, pWidthArray); + pWidthArray->AppendNew<CPDF_Number>(231); + Insert(0x20, 0x7d, pWidthArray.Get()); + pWidthArray->AppendNew<CPDF_Number>(326); + Insert(0xa0, 0xa0, pWidthArray.Get()); + pWidthArray->AppendNew<CPDF_Number>(327); + Insert(0xa1, 0xdf, pWidthArray.Get()); + pWidthArray->AppendNew<CPDF_Number>(631); + Insert(0x7e, 0x7e, pWidthArray.Get()); + break; + default: break; } pBaseDict->SetNewFor<CPDF_Name>("Subtype", "Type0"); @@ -700,13 +728,12 @@ pFontDict->SetNewFor<CPDF_Name>("Subtype", "CIDFontType2"); pFontDict->SetNewFor<CPDF_Name>("BaseFont", basefont); - CPDF_Dictionary* pCIDSysInfo = - pFontDict->SetNewFor<CPDF_Dictionary>("CIDSystemInfo"); + auto pCIDSysInfo = pFontDict->SetNewFor<CPDF_Dictionary>("CIDSystemInfo"); pCIDSysInfo->SetNewFor<CPDF_String>("Registry", "Adobe", false); pCIDSysInfo->SetNewFor<CPDF_String>("Ordering", ordering, false); pCIDSysInfo->SetNewFor<CPDF_Number>("Supplement", supplement); - CPDF_Array* pArray = pBaseDict->SetNewFor<CPDF_Array>("DescendantFonts"); - pArray->AddNew<CPDF_Reference>(GetDocument(), pFontDict->GetObjNum()); + auto pArray = pBaseDict->SetNewFor<CPDF_Array>("DescendantFonts"); + pArray->AppendNew<CPDF_Reference>(GetDocument(), pFontDict->GetObjNum()); return pFontDict; }
diff --git a/core/fpdfapi/page/cpdf_docpagedata.h b/core/fpdfapi/page/cpdf_docpagedata.h index 854d80d..59c0354 100644 --- a/core/fpdfapi/page/cpdf_docpagedata.h +++ b/core/fpdfapi/page/cpdf_docpagedata.h
@@ -1,4 +1,4 @@ -// Copyright 2016 PDFium Authors. All rights reserved. +// Copyright 2016 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -14,11 +14,11 @@ #include "core/fpdfapi/font/cpdf_font.h" #include "core/fpdfapi/page/cpdf_colorspace.h" #include "core/fpdfapi/parser/cpdf_document.h" +#include "core/fxcrt/bytestring.h" +#include "core/fxcrt/fx_codepage_forward.h" #include "core/fxcrt/fx_coordinates.h" -#include "core/fxcrt/fx_string.h" #include "core/fxcrt/observed_ptr.h" #include "core/fxcrt/retain_ptr.h" -#include "core/fxcrt/unowned_ptr.h" class CFX_Font; class CPDF_Dictionary; @@ -30,8 +30,8 @@ class CPDF_Stream; class CPDF_StreamAcc; -class CPDF_DocPageData : public CPDF_Document::PageDataIface, - public CPDF_Font::FormFactoryIface { +class CPDF_DocPageData final : public CPDF_Document::PageDataIface, + public CPDF_Font::FormFactoryIface { public: static CPDF_DocPageData* FromDocument(const CPDF_Document* pDoc); @@ -41,24 +41,27 @@ // CPDF_Document::PageDataIface: void ClearStockFont() override; RetainPtr<CPDF_StreamAcc> GetFontFileStreamAcc( - const CPDF_Stream* pFontStream) override; - void MaybePurgeFontFileStreamAcc(const CPDF_Stream* pFontStream) override; + RetainPtr<const CPDF_Stream> pFontStream) override; + void MaybePurgeFontFileStreamAcc( + RetainPtr<CPDF_StreamAcc>&& pStreamAcc) override; + void MaybePurgeImage(uint32_t dwStreamObjNum) override; // CPDF_Font::FormFactoryIFace: std::unique_ptr<CPDF_Font::FormIface> CreateForm( CPDF_Document* pDocument, - CPDF_Dictionary* pPageResources, - CPDF_Stream* pFormStream) override; + RetainPtr<CPDF_Dictionary> pPageResources, + RetainPtr<CPDF_Stream> pFormStream) override; bool IsForceClear() const { return m_bForceClear; } - RetainPtr<CPDF_Font> AddFont(std::unique_ptr<CFX_Font> pFont, int charset); - RetainPtr<CPDF_Font> GetFont(CPDF_Dictionary* pFontDict); + RetainPtr<CPDF_Font> AddFont(std::unique_ptr<CFX_Font> pFont, + FX_Charset charset); + RetainPtr<CPDF_Font> GetFont(RetainPtr<CPDF_Dictionary> pFontDict); RetainPtr<CPDF_Font> AddStandardFont(const ByteString& fontName, const CPDF_FontEncoding* pEncoding); RetainPtr<CPDF_Font> GetStandardFont(const ByteString& fontName, const CPDF_FontEncoding* pEncoding); -#if defined(OS_WIN) +#if BUILDFLAG(IS_WIN) RetainPtr<CPDF_Font> AddWindowsFont(LOGFONTA* pLogFont); #endif @@ -74,14 +77,15 @@ const CPDF_Dictionary* pResources, std::set<const CPDF_Object*>* pVisited); - RetainPtr<CPDF_Pattern> GetPattern(CPDF_Object* pPatternObj, - bool bShading, + RetainPtr<CPDF_Pattern> GetPattern(RetainPtr<CPDF_Object> pPatternObj, const CFX_Matrix& matrix); + RetainPtr<CPDF_ShadingPattern> GetShading(RetainPtr<CPDF_Object> pPatternObj, + const CFX_Matrix& matrix); RetainPtr<CPDF_Image> GetImage(uint32_t dwStreamObjNum); - void MaybePurgeImage(uint32_t dwStreamObjNum); - RetainPtr<CPDF_IccProfile> GetIccProfile(const CPDF_Stream* pProfileStream); + RetainPtr<CPDF_IccProfile> GetIccProfile( + RetainPtr<const CPDF_Stream> pProfileStream); private: // Loads a colorspace in a context that might be while loading another @@ -95,24 +99,27 @@ std::set<const CPDF_Object*>* pVisited, std::set<const CPDF_Object*>* pVisitedInternal); - size_t CalculateEncodingDict(int charset, CPDF_Dictionary* pBaseDict); - CPDF_Dictionary* ProcessbCJK( - CPDF_Dictionary* pBaseDict, - int charset, + size_t CalculateEncodingDict(FX_Charset charset, CPDF_Dictionary* pBaseDict); + RetainPtr<CPDF_Dictionary> ProcessbCJK( + RetainPtr<CPDF_Dictionary> pBaseDict, + FX_Charset charset, ByteString basefont, std::function<void(wchar_t, wchar_t, CPDF_Array*)> Insert); - void Clear(bool bForceRelease); bool m_bForceClear = false; // Specific destruction order may be required between maps. std::map<ByteString, RetainPtr<const CPDF_Stream>> m_HashProfileMap; - std::map<const CPDF_Object*, ObservedPtr<CPDF_ColorSpace>> m_ColorSpaceMap; - std::map<const CPDF_Stream*, RetainPtr<CPDF_StreamAcc>> m_FontFileMap; - std::map<const CPDF_Stream*, ObservedPtr<CPDF_IccProfile>> m_IccProfileMap; - std::map<const CPDF_Object*, ObservedPtr<CPDF_Pattern>> m_PatternMap; + std::map<RetainPtr<const CPDF_Array>, ObservedPtr<CPDF_ColorSpace>> + m_ColorSpaceMap; + std::map<RetainPtr<const CPDF_Stream>, RetainPtr<CPDF_StreamAcc>> + m_FontFileMap; + std::map<RetainPtr<const CPDF_Stream>, ObservedPtr<CPDF_IccProfile>> + m_IccProfileMap; + std::map<RetainPtr<const CPDF_Object>, ObservedPtr<CPDF_Pattern>> + m_PatternMap; std::map<uint32_t, RetainPtr<CPDF_Image>> m_ImageMap; - std::map<const CPDF_Dictionary*, ObservedPtr<CPDF_Font>> m_FontMap; + std::map<RetainPtr<const CPDF_Dictionary>, ObservedPtr<CPDF_Font>> m_FontMap; }; #endif // CORE_FPDFAPI_PAGE_CPDF_DOCPAGEDATA_H_
diff --git a/core/fpdfapi/page/cpdf_expintfunc.cpp b/core/fpdfapi/page/cpdf_expintfunc.cpp index 7194f97..a8de8b9 100644 --- a/core/fpdfapi/page/cpdf_expintfunc.cpp +++ b/core/fpdfapi/page/cpdf_expintfunc.cpp
@@ -1,4 +1,4 @@ -// Copyright 2017 PDFium Authors. All rights reserved. +// Copyright 2017 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -6,41 +6,44 @@ #include "core/fpdfapi/page/cpdf_expintfunc.h" +#include <math.h> + #include "core/fpdfapi/parser/cpdf_array.h" #include "core/fpdfapi/parser/cpdf_dictionary.h" #include "core/fpdfapi/parser/cpdf_number.h" +#include "core/fxcrt/data_vector.h" +#include "core/fxcrt/fx_2d_size.h" #include "core/fxcrt/fx_safe_types.h" -#include "third_party/base/stl_util.h" +#include "core/fxcrt/stl_util.h" CPDF_ExpIntFunc::CPDF_ExpIntFunc() - : CPDF_Function(Type::kType2ExpotentialInterpolation) {} + : CPDF_Function(Type::kType2ExponentialInterpolation) {} CPDF_ExpIntFunc::~CPDF_ExpIntFunc() = default; -bool CPDF_ExpIntFunc::v_Init(const CPDF_Object* pObj, - std::set<const CPDF_Object*>* pVisited) { - const CPDF_Dictionary* pDict = pObj->GetDict(); +bool CPDF_ExpIntFunc::v_Init(const CPDF_Object* pObj, VisitedSet* pVisited) { + RetainPtr<const CPDF_Dictionary> pDict = pObj->GetDict(); if (!pDict) return false; - const CPDF_Number* pExponent = ToNumber(pDict->GetObjectFor("N")); + RetainPtr<const CPDF_Number> pExponent = pDict->GetNumberFor("N"); if (!pExponent) return false; m_Exponent = pExponent->GetNumber(); - const CPDF_Array* pArray0 = pDict->GetArrayFor("C0"); + RetainPtr<const CPDF_Array> pArray0 = pDict->GetArrayFor("C0"); if (pArray0 && m_nOutputs == 0) - m_nOutputs = pArray0->size(); + m_nOutputs = fxcrt::CollectionSize<uint32_t>(*pArray0); if (m_nOutputs == 0) m_nOutputs = 1; - const CPDF_Array* pArray1 = pDict->GetArrayFor("C1"); - m_BeginValues = pdfium::Vector2D<float>(m_nOutputs, 2); - m_EndValues = pdfium::Vector2D<float>(m_nOutputs, 2); + RetainPtr<const CPDF_Array> pArray1 = pDict->GetArrayFor("C1"); + m_BeginValues = DataVector<float>(Fx2DSizeOrDie(m_nOutputs, 2)); + m_EndValues = DataVector<float>(m_BeginValues.size()); for (uint32_t i = 0; i < m_nOutputs; i++) { - m_BeginValues[i] = pArray0 ? pArray0->GetNumberAt(i) : 0.0f; - m_EndValues[i] = pArray1 ? pArray1->GetNumberAt(i) : 1.0f; + m_BeginValues[i] = pArray0 ? pArray0->GetFloatAt(i) : 0.0f; + m_EndValues[i] = pArray1 ? pArray1->GetFloatAt(i) : 1.0f; } FX_SAFE_UINT32 nOutputs = m_nOutputs; @@ -53,12 +56,13 @@ return true; } -bool CPDF_ExpIntFunc::v_Call(const float* inputs, float* results) const { +bool CPDF_ExpIntFunc::v_Call(pdfium::span<const float> inputs, + pdfium::span<float> results) const { for (uint32_t i = 0; i < m_nInputs; i++) { for (uint32_t j = 0; j < m_nOrigOutputs; j++) { results[i * m_nOrigOutputs + j] = - m_BeginValues[j] + FXSYS_pow(inputs[i], m_Exponent) * - (m_EndValues[j] - m_BeginValues[j]); + m_BeginValues[j] + + powf(inputs[i], m_Exponent) * (m_EndValues[j] - m_BeginValues[j]); } } return true;
diff --git a/core/fpdfapi/page/cpdf_expintfunc.h b/core/fpdfapi/page/cpdf_expintfunc.h index 95bdab6..08b12fd 100644 --- a/core/fpdfapi/page/cpdf_expintfunc.h +++ b/core/fpdfapi/page/cpdf_expintfunc.h
@@ -1,4 +1,4 @@ -// Copyright 2017 PDFium Authors. All rights reserved. +// Copyright 2017 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -7,25 +7,36 @@ #ifndef CORE_FPDFAPI_PAGE_CPDF_EXPINTFUNC_H_ #define CORE_FPDFAPI_PAGE_CPDF_EXPINTFUNC_H_ -#include <set> -#include <vector> - #include "core/fpdfapi/page/cpdf_function.h" +#include "core/fxcrt/data_vector.h" + +#if defined(_SKIA_SUPPORT_) +#include "third_party/base/span.h" +#endif class CPDF_ExpIntFunc final : public CPDF_Function { public: CPDF_ExpIntFunc(); ~CPDF_ExpIntFunc() override; - // CPDF_Function - bool v_Init(const CPDF_Object* pObj, - std::set<const CPDF_Object*>* pVisited) override; - bool v_Call(const float* inputs, float* results) const override; + // CPDF_Function: + bool v_Init(const CPDF_Object* pObj, VisitedSet* pVisited) override; + bool v_Call(pdfium::span<const float> inputs, + pdfium::span<float> results) const override; + uint32_t GetOrigOutputs() const { return m_nOrigOutputs; } + float GetExponent() const { return m_Exponent; } + +#if defined(_SKIA_SUPPORT_) + pdfium::span<const float> GetBeginValues() const { return m_BeginValues; } + pdfium::span<const float> GetEndValues() const { return m_EndValues; } +#endif + + private: uint32_t m_nOrigOutputs = 0; float m_Exponent = 0.0f; - std::vector<float> m_BeginValues; - std::vector<float> m_EndValues; + DataVector<float> m_BeginValues; + DataVector<float> m_EndValues; }; #endif // CORE_FPDFAPI_PAGE_CPDF_EXPINTFUNC_H_
diff --git a/core/fpdfapi/page/cpdf_form.cpp b/core/fpdfapi/page/cpdf_form.cpp index ab3296e..90a8650 100644 --- a/core/fpdfapi/page/cpdf_form.cpp +++ b/core/fpdfapi/page/cpdf_form.cpp
@@ -1,4 +1,4 @@ -// Copyright 2016 PDFium Authors. All rights reserved. +// Copyright 2016 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -7,6 +7,7 @@ #include "core/fpdfapi/page/cpdf_form.h" #include <algorithm> +#include <memory> #include "core/fpdfapi/page/cpdf_contentparser.h" #include "core/fpdfapi/page/cpdf_imageobject.h" @@ -15,7 +16,7 @@ #include "core/fpdfapi/parser/cpdf_dictionary.h" #include "core/fpdfapi/parser/cpdf_stream.h" #include "core/fxge/dib/cfx_dibitmap.h" -#include "third_party/base/ptr_util.h" +#include "third_party/base/check_op.h" // static CPDF_Dictionary* CPDF_Form::ChooseResourcesDict( @@ -28,22 +29,27 @@ } CPDF_Form::CPDF_Form(CPDF_Document* pDoc, - CPDF_Dictionary* pPageResources, - CPDF_Stream* pFormStream) - : CPDF_Form(pDoc, pPageResources, pFormStream, nullptr) {} + RetainPtr<CPDF_Dictionary> pPageResources, + RetainPtr<CPDF_Stream> pFormStream) + : CPDF_Form(pDoc, + std::move(pPageResources), + std::move(pFormStream), + nullptr) {} CPDF_Form::CPDF_Form(CPDF_Document* pDoc, - CPDF_Dictionary* pPageResources, - CPDF_Stream* pFormStream, + RetainPtr<CPDF_Dictionary> pPageResources, + RetainPtr<CPDF_Stream> pFormStream, CPDF_Dictionary* pParentResources) - : CPDF_PageObjectHolder( - pDoc, - pFormStream->GetDict(), - pPageResources, - ChooseResourcesDict(pFormStream->GetDict()->GetDictFor("Resources"), - pParentResources, - pPageResources)), - m_pFormStream(pFormStream) { + : CPDF_PageObjectHolder(pDoc, + pFormStream->GetMutableDict(), + pPageResources, + pdfium::WrapRetain(ChooseResourcesDict( + pFormStream->GetMutableDict() + ->GetMutableDictFor("Resources") + .Get(), + pParentResources, + pPageResources.Get()))), + m_pFormStream(std::move(pFormStream)) { LoadTransparencyInfo(); } @@ -71,16 +77,11 @@ return; if (GetParseState() == ParseState::kNotParsed) { - if (!pParsedSet) { - if (!m_ParsedSet) - m_ParsedSet = pdfium::MakeUnique<std::set<const uint8_t*>>(); - pParsedSet = m_ParsedSet.get(); - } - StartParse(pdfium::MakeUnique<CPDF_ContentParser>( - this, pGraphicStates, pParentMatrix, pType3Char, pParsedSet)); + StartParse(std::make_unique<CPDF_ContentParser>( + GetStream(), this, pGraphicStates, pParentMatrix, pType3Char, + pParsedSet ? pParsedSet : &m_ParsedSet)); } - - ASSERT(GetParseState() == ParseState::kParsing); + DCHECK_EQ(GetParseState(), ParseState::kParsing); ContinueParse(nullptr); } @@ -106,18 +107,18 @@ return CFX_FloatRect(left, bottom, right, top); } -const CPDF_Stream* CPDF_Form::GetStream() const { - return m_pFormStream.Get(); +RetainPtr<const CPDF_Stream> CPDF_Form::GetStream() const { + return m_pFormStream; } -Optional<std::pair<RetainPtr<CFX_DIBitmap>, CFX_Matrix>> +absl::optional<std::pair<RetainPtr<CFX_DIBitmap>, CFX_Matrix>> CPDF_Form::GetBitmapAndMatrixFromSoleImageOfForm() const { if (GetPageObjectCount() != 1) - return {}; + return absl::nullopt; CPDF_ImageObject* pImageObject = (*begin())->AsImage(); if (!pImageObject) - return {}; + return absl::nullopt; return {{pImageObject->GetIndependentBitmap(), pImageObject->matrix()}}; }
diff --git a/core/fpdfapi/page/cpdf_form.h b/core/fpdfapi/page/cpdf_form.h index e8b9d1f..9052b9d 100644 --- a/core/fpdfapi/page/cpdf_form.h +++ b/core/fpdfapi/page/cpdf_form.h
@@ -1,4 +1,4 @@ -// Copyright 2016 PDFium Authors. All rights reserved. +// Copyright 2016 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -7,18 +7,17 @@ #ifndef CORE_FPDFAPI_PAGE_CPDF_FORM_H_ #define CORE_FPDFAPI_PAGE_CPDF_FORM_H_ -#include <memory> #include <set> #include <utility> #include "core/fpdfapi/font/cpdf_font.h" #include "core/fpdfapi/page/cpdf_pageobjectholder.h" +#include "core/fxcrt/retain_ptr.h" class CFX_Matrix; class CPDF_AllStates; class CPDF_Dictionary; class CPDF_Document; -class CPDF_ImageObject; class CPDF_Stream; class CPDF_Type3Char; @@ -31,11 +30,11 @@ CPDF_Dictionary* pPageResources); CPDF_Form(CPDF_Document* pDocument, - CPDF_Dictionary* pPageResources, - CPDF_Stream* pFormStream); + RetainPtr<CPDF_Dictionary> pPageResources, + RetainPtr<CPDF_Stream> pFormStream); CPDF_Form(CPDF_Document* pDocument, - CPDF_Dictionary* pPageResources, - CPDF_Stream* pFormStream, + RetainPtr<CPDF_Dictionary> pPageResources, + RetainPtr<CPDF_Stream> pFormStream, CPDF_Dictionary* pParentResources); ~CPDF_Form() override; @@ -43,7 +42,7 @@ void ParseContentForType3Char(CPDF_Type3Char* pType3Char) override; bool HasPageObjects() const override; CFX_FloatRect CalcBoundingBox() const override; - Optional<std::pair<RetainPtr<CFX_DIBitmap>, CFX_Matrix>> + absl::optional<std::pair<RetainPtr<CFX_DIBitmap>, CFX_Matrix>> GetBitmapAndMatrixFromSoleImageOfForm() const override; void ParseContent(); @@ -51,7 +50,7 @@ const CFX_Matrix* pParentMatrix, std::set<const uint8_t*>* pParsedSet); - const CPDF_Stream* GetStream() const; + RetainPtr<const CPDF_Stream> GetStream() const; private: void ParseContentInternal(const CPDF_AllStates* pGraphicStates, @@ -59,7 +58,7 @@ CPDF_Type3Char* pType3Char, std::set<const uint8_t*>* pParsedSet); - std::unique_ptr<std::set<const uint8_t*>> m_ParsedSet; + std::set<const uint8_t*> m_ParsedSet; RetainPtr<CPDF_Stream> const m_pFormStream; };
diff --git a/core/fpdfapi/page/cpdf_formobject.cpp b/core/fpdfapi/page/cpdf_formobject.cpp index a7c2643..8b270ca 100644 --- a/core/fpdfapi/page/cpdf_formobject.cpp +++ b/core/fpdfapi/page/cpdf_formobject.cpp
@@ -1,4 +1,4 @@ -// Copyright 2016 PDFium Authors. All rights reserved. +// Copyright 2016 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -17,11 +17,12 @@ m_pForm(std::move(pForm)), m_FormMatrix(matrix) {} -CPDF_FormObject::~CPDF_FormObject() {} +CPDF_FormObject::~CPDF_FormObject() = default; void CPDF_FormObject::Transform(const CFX_Matrix& matrix) { m_FormMatrix.Concat(matrix); CalcBoundingBox(); + SetDirty(true); } bool CPDF_FormObject::IsForm() const { @@ -37,9 +38,14 @@ } CPDF_PageObject::Type CPDF_FormObject::GetType() const { - return FORM; + return Type::kForm; } void CPDF_FormObject::CalcBoundingBox() { SetRect(m_FormMatrix.TransformRect(m_pForm->CalcBoundingBox())); } + +void CPDF_FormObject::SetFormMatrix(const CFX_Matrix& matrix) { + m_FormMatrix = matrix; + CalcBoundingBox(); +}
diff --git a/core/fpdfapi/page/cpdf_formobject.h b/core/fpdfapi/page/cpdf_formobject.h index c24bfbf..a18a774 100644 --- a/core/fpdfapi/page/cpdf_formobject.h +++ b/core/fpdfapi/page/cpdf_formobject.h
@@ -1,4 +1,4 @@ -// Copyright 2016 PDFium Authors. All rights reserved. +// Copyright 2016 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -31,6 +31,7 @@ void CalcBoundingBox(); const CPDF_Form* form() const { return m_pForm.get(); } const CFX_Matrix& form_matrix() const { return m_FormMatrix; } + void SetFormMatrix(const CFX_Matrix& matrix); private: std::unique_ptr<CPDF_Form> const m_pForm;
diff --git a/core/fpdfapi/page/cpdf_function.cpp b/core/fpdfapi/page/cpdf_function.cpp index 688c48e..85b9e41 100644 --- a/core/fpdfapi/page/cpdf_function.cpp +++ b/core/fpdfapi/page/cpdf_function.cpp
@@ -1,4 +1,4 @@ -// Copyright 2017 PDFium Authors. All rights reserved. +// Copyright 2017 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -6,6 +6,7 @@ #include "core/fpdfapi/page/cpdf_function.h" +#include <utility> #include <vector> #include "core/fpdfapi/page/cpdf_expintfunc.h" @@ -17,26 +18,45 @@ #include "core/fpdfapi/parser/cpdf_stream.h" #include "core/fpdfapi/parser/fpdf_parser_utility.h" #include "core/fxcrt/fx_safe_types.h" -#include "third_party/base/ptr_util.h" -#include "third_party/base/stl_util.h" +#include "core/fxcrt/scoped_set_insertion.h" +#include "core/fxcrt/stl_util.h" +#include "third_party/base/containers/contains.h" +#include "third_party/base/cxx17_backports.h" + +namespace { + +CPDF_Function::Type IntegerToFunctionType(int iType) { + switch (iType) { + case 0: + case 2: + case 3: + case 4: + return static_cast<CPDF_Function::Type>(iType); + default: + return CPDF_Function::Type::kTypeInvalid; + } +} + +} // namespace // static std::unique_ptr<CPDF_Function> CPDF_Function::Load( - const CPDF_Object* pFuncObj) { - std::set<const CPDF_Object*> visited; - return Load(pFuncObj, &visited); + RetainPtr<const CPDF_Object> pFuncObj) { + VisitedSet visited; + return Load(std::move(pFuncObj), &visited); } // static std::unique_ptr<CPDF_Function> CPDF_Function::Load( - const CPDF_Object* pFuncObj, - std::set<const CPDF_Object*>* pVisited) { + RetainPtr<const CPDF_Object> pFuncObj, + VisitedSet* pVisited) { if (!pFuncObj) return nullptr; - if (pdfium::ContainsKey(*pVisited, pFuncObj)) + if (pdfium::Contains(*pVisited, pFuncObj)) return nullptr; - pdfium::ScopedSetInsertion<const CPDF_Object*> insertion(pVisited, pFuncObj); + + ScopedSetInsertion<VisitedSet::value_type> insertion(pVisited, pFuncObj); int iType = -1; if (const CPDF_Stream* pStream = pFuncObj->AsStream()) @@ -47,13 +67,13 @@ std::unique_ptr<CPDF_Function> pFunc; Type type = IntegerToFunctionType(iType); if (type == Type::kType0Sampled) - pFunc = pdfium::MakeUnique<CPDF_SampledFunc>(); - else if (type == Type::kType2ExpotentialInterpolation) - pFunc = pdfium::MakeUnique<CPDF_ExpIntFunc>(); + pFunc = std::make_unique<CPDF_SampledFunc>(); + else if (type == Type::kType2ExponentialInterpolation) + pFunc = std::make_unique<CPDF_ExpIntFunc>(); else if (type == Type::kType3Stitching) - pFunc = pdfium::MakeUnique<CPDF_StitchFunc>(); + pFunc = std::make_unique<CPDF_StitchFunc>(); else if (type == Type::kType4PostScript) - pFunc = pdfium::MakeUnique<CPDF_PSFunc>(); + pFunc = std::make_unique<CPDF_PSFunc>(); if (!pFunc || !pFunc->Init(pFuncObj, pVisited)) return nullptr; @@ -61,42 +81,28 @@ return pFunc; } -// static -CPDF_Function::Type CPDF_Function::IntegerToFunctionType(int iType) { - switch (iType) { - case 0: - case 2: - case 3: - case 4: - return static_cast<Type>(iType); - default: - return Type::kTypeInvalid; - } -} - CPDF_Function::CPDF_Function(Type type) : m_Type(type) {} CPDF_Function::~CPDF_Function() = default; -bool CPDF_Function::Init(const CPDF_Object* pObj, - std::set<const CPDF_Object*>* pVisited) { +bool CPDF_Function::Init(const CPDF_Object* pObj, VisitedSet* pVisited) { const CPDF_Stream* pStream = pObj->AsStream(); - const CPDF_Dictionary* pDict = - pStream ? pStream->GetDict() : pObj->AsDictionary(); + RetainPtr<const CPDF_Dictionary> pDict = + pStream ? pStream->GetDict() : pdfium::WrapRetain(pObj->AsDictionary()); - const CPDF_Array* pDomains = pDict->GetArrayFor("Domain"); + RetainPtr<const CPDF_Array> pDomains = pDict->GetArrayFor("Domain"); if (!pDomains) return false; - m_nInputs = pDomains->size() / 2; + m_nInputs = fxcrt::CollectionSize<uint32_t>(*pDomains) / 2; if (m_nInputs == 0) return false; size_t nInputs = m_nInputs * 2; - m_Domains = ReadArrayElementsToVector(pDomains, nInputs); + m_Domains = ReadArrayElementsToVector(pDomains.Get(), nInputs); - const CPDF_Array* pRanges = pDict->GetArrayFor("Range"); - m_nOutputs = pRanges ? pRanges->size() / 2 : 0; + RetainPtr<const CPDF_Array> pRanges = pDict->GetArrayFor("Range"); + m_nOutputs = pRanges ? fxcrt::CollectionSize<uint32_t>(*pRanges) / 2 : 0; // Ranges are required for type 0 and type 4 functions. A non-zero // |m_nOutputs| here implied Ranges meets the requirements. @@ -107,7 +113,7 @@ if (m_nOutputs > 0) { size_t nOutputs = m_nOutputs * 2; - m_Ranges = ReadArrayElementsToVector(pRanges, nOutputs); + m_Ranges = ReadArrayElementsToVector(pRanges.Get(), nOutputs); } uint32_t old_outputs = m_nOutputs; @@ -122,30 +128,36 @@ return true; } -bool CPDF_Function::Call(const float* inputs, - uint32_t ninputs, - float* results, - int* nresults) const { - if (m_nInputs != ninputs) - return false; +absl::optional<uint32_t> CPDF_Function::Call( + pdfium::span<const float> inputs, + pdfium::span<float> results) const { + if (m_nInputs != inputs.size()) + return absl::nullopt; - *nresults = m_nOutputs; std::vector<float> clamped_inputs(m_nInputs); for (uint32_t i = 0; i < m_nInputs; i++) { - clamped_inputs[i] = - pdfium::clamp(inputs[i], m_Domains[i * 2], m_Domains[i * 2 + 1]); + float domain1 = m_Domains[i * 2]; + float domain2 = m_Domains[i * 2 + 1]; + if (domain1 > domain2) + return absl::nullopt; + + clamped_inputs[i] = pdfium::clamp(inputs[i], domain1, domain2); } - if (!v_Call(clamped_inputs.data(), results)) - return false; + if (!v_Call(clamped_inputs, results)) + return absl::nullopt; if (m_Ranges.empty()) - return true; + return m_nOutputs; for (uint32_t i = 0; i < m_nOutputs; i++) { - results[i] = - pdfium::clamp(results[i], m_Ranges[i * 2], m_Ranges[i * 2 + 1]); + float range1 = m_Ranges[i * 2]; + float range2 = m_Ranges[i * 2 + 1]; + if (range1 > range2) + return absl::nullopt; + + results[i] = pdfium::clamp(results[i], range1, range2); } - return true; + return m_nOutputs; } // See PDF Reference 1.7, page 170. @@ -158,6 +170,7 @@ return ymin + (divisor ? (x - xmin) * (ymax - ymin) / divisor : 0); } +#if defined(_SKIA_SUPPORT_) const CPDF_SampledFunc* CPDF_Function::ToSampledFunc() const { return m_Type == Type::kType0Sampled ? static_cast<const CPDF_SampledFunc*>(this) @@ -165,7 +178,7 @@ } const CPDF_ExpIntFunc* CPDF_Function::ToExpIntFunc() const { - return m_Type == Type::kType2ExpotentialInterpolation + return m_Type == Type::kType2ExponentialInterpolation ? static_cast<const CPDF_ExpIntFunc*>(this) : nullptr; } @@ -175,3 +188,4 @@ ? static_cast<const CPDF_StitchFunc*>(this) : nullptr; } +#endif // defined(_SKIA_SUPPORT_)
diff --git a/core/fpdfapi/page/cpdf_function.h b/core/fpdfapi/page/cpdf_function.h index 5f4e125..faddb4e 100644 --- a/core/fpdfapi/page/cpdf_function.h +++ b/core/fpdfapi/page/cpdf_function.h
@@ -1,4 +1,4 @@ -// Copyright 2017 PDFium Authors. All rights reserved. +// Copyright 2017 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -11,6 +11,10 @@ #include <set> #include <vector> +#include "core/fxcrt/retain_ptr.h" +#include "third_party/abseil-cpp/absl/types/optional.h" +#include "third_party/base/span.h" + class CPDF_ExpIntFunc; class CPDF_Object; class CPDF_SampledFunc; @@ -18,23 +22,22 @@ class CPDF_Function { public: + // Valid values are from ISO 32000-1:2008 spec, table 38. DO NOT CHANGE. enum class Type { kTypeInvalid = -1, kType0Sampled = 0, - kType2ExpotentialInterpolation = 2, + kType2ExponentialInterpolation = 2, kType3Stitching = 3, kType4PostScript = 4, }; - static std::unique_ptr<CPDF_Function> Load(const CPDF_Object* pFuncObj); - static Type IntegerToFunctionType(int iType); + static std::unique_ptr<CPDF_Function> Load( + RetainPtr<const CPDF_Object> pFuncObj); virtual ~CPDF_Function(); - bool Call(const float* inputs, - uint32_t ninputs, - float* results, - int* nresults) const; + absl::optional<uint32_t> Call(pdfium::span<const float> inputs, + pdfium::span<float> results) const; uint32_t CountInputs() const { return m_nInputs; } uint32_t CountOutputs() const { return m_nOutputs; } float GetDomain(int i) const { return m_Domains[i]; } @@ -45,24 +48,27 @@ float ymin, float ymax) const; +#if defined(_SKIA_SUPPORT_) const CPDF_SampledFunc* ToSampledFunc() const; const CPDF_ExpIntFunc* ToExpIntFunc() const; const CPDF_StitchFunc* ToStitchFunc() const; +#endif // defined(_SKIA_SUPPORT_) protected: explicit CPDF_Function(Type type); + using VisitedSet = std::set<RetainPtr<const CPDF_Object>>; static std::unique_ptr<CPDF_Function> Load( - const CPDF_Object* pFuncObj, - std::set<const CPDF_Object*>* pVisited); - bool Init(const CPDF_Object* pObj, std::set<const CPDF_Object*>* pVisited); - virtual bool v_Init(const CPDF_Object* pObj, - std::set<const CPDF_Object*>* pVisited) = 0; - virtual bool v_Call(const float* inputs, float* results) const = 0; + RetainPtr<const CPDF_Object> pFuncObj, + VisitedSet* pVisited); + bool Init(const CPDF_Object* pObj, VisitedSet* pVisited); + virtual bool v_Init(const CPDF_Object* pObj, VisitedSet* pVisited) = 0; + virtual bool v_Call(pdfium::span<const float> inputs, + pdfium::span<float> results) const = 0; const Type m_Type; - uint32_t m_nInputs; - uint32_t m_nOutputs; + uint32_t m_nInputs = 0; + uint32_t m_nOutputs = 0; std::vector<float> m_Domains; std::vector<float> m_Ranges; };
diff --git a/core/fpdfapi/page/cpdf_function_unittest.cpp b/core/fpdfapi/page/cpdf_function_unittest.cpp new file mode 100644 index 0000000..af0ca03 --- /dev/null +++ b/core/fpdfapi/page/cpdf_function_unittest.cpp
@@ -0,0 +1,43 @@ +// Copyright 2020 The PDFium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "core/fpdfapi/page/cpdf_function.h" + +#include "core/fpdfapi/parser/cpdf_array.h" +#include "core/fpdfapi/parser/cpdf_dictionary.h" +#include "core/fpdfapi/parser/cpdf_number.h" +#include "core/fxcrt/retain_ptr.h" +#include "testing/gtest/include/gtest/gtest.h" + +TEST(CPDFFunction, BadFunctionType) { + auto pDict = pdfium::MakeRetain<CPDF_Dictionary>(); + pDict->SetNewFor<CPDF_Number>("FunctionType", -2); + EXPECT_FALSE(CPDF_Function::Load(pDict)); + + pDict->SetNewFor<CPDF_Number>("FunctionType", 5); + EXPECT_FALSE(CPDF_Function::Load(pDict)); +} + +TEST(CPDFFunction, NoDomain) { + auto pDict = pdfium::MakeRetain<CPDF_Dictionary>(); + pDict->SetNewFor<CPDF_Number>("FunctionType", 0); + EXPECT_FALSE(CPDF_Function::Load(pDict)); +} + +TEST(CPDFFunction, EmptyDomain) { + auto pDict = pdfium::MakeRetain<CPDF_Dictionary>(); + pDict->SetNewFor<CPDF_Number>("FunctionType", 0); + pDict->SetNewFor<CPDF_Array>("Domain"); + EXPECT_FALSE(CPDF_Function::Load(pDict)); +} + +TEST(CPDFFunction, NoRange) { + auto pDict = pdfium::MakeRetain<CPDF_Dictionary>(); + pDict->SetNewFor<CPDF_Number>("FunctionType", 0); + + auto pArray = pDict->SetNewFor<CPDF_Array>("Domain"); + pArray->AppendNew<CPDF_Number>(0); + pArray->AppendNew<CPDF_Number>(10); + EXPECT_FALSE(CPDF_Function::Load(pDict)); +}
diff --git a/core/fpdfapi/page/cpdf_generalstate.cpp b/core/fpdfapi/page/cpdf_generalstate.cpp index 6463b57..8ebefa3 100644 --- a/core/fpdfapi/page/cpdf_generalstate.cpp +++ b/core/fpdfapi/page/cpdf_generalstate.cpp
@@ -1,4 +1,4 @@ -// Copyright 2016 PDFium Authors. All rights reserved. +// Copyright 2016 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -6,8 +6,11 @@ #include "core/fpdfapi/page/cpdf_generalstate.h" +#include <utility> + #include "core/fpdfapi/page/cpdf_transferfunc.h" -#include "core/fpdfapi/parser/cpdf_document.h" +#include "core/fpdfapi/parser/cpdf_dictionary.h" +#include "core/fpdfapi/parser/cpdf_object.h" namespace { @@ -66,12 +69,12 @@ } // namespace -CPDF_GeneralState::CPDF_GeneralState() {} +CPDF_GeneralState::CPDF_GeneralState() = default; CPDF_GeneralState::CPDF_GeneralState(const CPDF_GeneralState& that) : m_Ref(that.m_Ref) {} -CPDF_GeneralState::~CPDF_GeneralState() {} +CPDF_GeneralState::~CPDF_GeneralState() = default; void CPDF_GeneralState::SetRenderIntent(const ByteString& ri) { m_Ref.GetPrivateCopy()->m_RenderIntent = RI_StringToId(ri); @@ -142,22 +145,27 @@ m_Ref.GetPrivateCopy()->m_StrokeAlpha = alpha; } -CPDF_Object* CPDF_GeneralState::GetSoftMask() const { +RetainPtr<const CPDF_Dictionary> CPDF_GeneralState::GetSoftMask() const { const StateData* pData = m_Ref.GetObject(); - return pData ? pData->m_pSoftMask.Get() : nullptr; + return pData ? pData->m_pSoftMask : nullptr; } -void CPDF_GeneralState::SetSoftMask(CPDF_Object* pObject) { - m_Ref.GetPrivateCopy()->m_pSoftMask.Reset(pObject); -} - -const CPDF_Object* CPDF_GeneralState::GetTR() const { +RetainPtr<CPDF_Dictionary> CPDF_GeneralState::GetMutableSoftMask() { const StateData* pData = m_Ref.GetObject(); - return pData ? pData->m_pTR.Get() : nullptr; + return pData ? pData->m_pSoftMask : nullptr; } -void CPDF_GeneralState::SetTR(CPDF_Object* pObject) { - m_Ref.GetPrivateCopy()->m_pTR.Reset(pObject); +void CPDF_GeneralState::SetSoftMask(RetainPtr<CPDF_Dictionary> pDict) { + m_Ref.GetPrivateCopy()->m_pSoftMask = std::move(pDict); +} + +RetainPtr<const CPDF_Object> CPDF_GeneralState::GetTR() const { + const StateData* pData = m_Ref.GetObject(); + return pData ? pData->m_pTR : nullptr; +} + +void CPDF_GeneralState::SetTR(RetainPtr<const CPDF_Object> pObject) { + m_Ref.GetPrivateCopy()->m_pTR = std::move(pObject); } RetainPtr<CPDF_TransferFunc> CPDF_GeneralState::GetTransferFunc() const { @@ -165,9 +173,8 @@ return pData ? pData->m_pTransferFunc : nullptr; } -void CPDF_GeneralState::SetTransferFunc( - const RetainPtr<CPDF_TransferFunc>& pFunc) { - m_Ref.GetPrivateCopy()->m_pTransferFunc = pFunc; +void CPDF_GeneralState::SetTransferFunc(RetainPtr<CPDF_TransferFunc> pFunc) { + m_Ref.GetPrivateCopy()->m_pTransferFunc = std::move(pFunc); } void CPDF_GeneralState::SetBlendMode(const ByteString& mode) { @@ -211,16 +218,16 @@ m_Ref.GetPrivateCopy()->m_OPMode = mode; } -void CPDF_GeneralState::SetBG(CPDF_Object* pObject) { - m_Ref.GetPrivateCopy()->m_pBG.Reset(pObject); +void CPDF_GeneralState::SetBG(RetainPtr<const CPDF_Object> pObject) { + m_Ref.GetPrivateCopy()->m_pBG = std::move(pObject); } -void CPDF_GeneralState::SetUCR(CPDF_Object* pObject) { - m_Ref.GetPrivateCopy()->m_pUCR.Reset(pObject); +void CPDF_GeneralState::SetUCR(RetainPtr<const CPDF_Object> pObject) { + m_Ref.GetPrivateCopy()->m_pUCR = std::move(pObject); } -void CPDF_GeneralState::SetHT(CPDF_Object* pObject) { - m_Ref.GetPrivateCopy()->m_pHT.Reset(pObject); +void CPDF_GeneralState::SetHT(RetainPtr<const CPDF_Object> pObject) { + m_Ref.GetPrivateCopy()->m_pHT = std::move(pObject); } void CPDF_GeneralState::SetFlatness(float flatness) {
diff --git a/core/fpdfapi/page/cpdf_generalstate.h b/core/fpdfapi/page/cpdf_generalstate.h index f374380..2fb2285 100644 --- a/core/fpdfapi/page/cpdf_generalstate.h +++ b/core/fpdfapi/page/cpdf_generalstate.h
@@ -1,4 +1,4 @@ -// Copyright 2016 PDFium Authors. All rights reserved. +// Copyright 2016 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -8,12 +8,13 @@ #define CORE_FPDFAPI_PAGE_CPDF_GENERALSTATE_H_ #include "constants/transparency.h" +#include "core/fxcrt/bytestring.h" #include "core/fxcrt/fx_coordinates.h" -#include "core/fxcrt/fx_string.h" #include "core/fxcrt/retain_ptr.h" #include "core/fxcrt/shared_copy_on_write.h" -#include "core/fxge/fx_dib.h" +#include "core/fxge/dib/fx_dib.h" +class CPDF_Dictionary; class CPDF_Object; class CPDF_TransferFunc; @@ -38,14 +39,15 @@ float GetStrokeAlpha() const; void SetStrokeAlpha(float alpha); - CPDF_Object* GetSoftMask() const; - void SetSoftMask(CPDF_Object* pObject); + RetainPtr<const CPDF_Dictionary> GetSoftMask() const; + RetainPtr<CPDF_Dictionary> GetMutableSoftMask(); + void SetSoftMask(RetainPtr<CPDF_Dictionary> pDict); - const CPDF_Object* GetTR() const; - void SetTR(CPDF_Object* pObject); + RetainPtr<const CPDF_Object> GetTR() const; + void SetTR(RetainPtr<const CPDF_Object> pObject); RetainPtr<CPDF_TransferFunc> GetTransferFunc() const; - void SetTransferFunc(const RetainPtr<CPDF_TransferFunc>& pFunc); + void SetTransferFunc(RetainPtr<CPDF_TransferFunc> pFunc); void SetBlendMode(const ByteString& mode); @@ -61,9 +63,9 @@ int GetOPMode() const; void SetOPMode(int mode); - void SetBG(CPDF_Object* pObject); - void SetUCR(CPDF_Object* pObject); - void SetHT(CPDF_Object* pObject); + void SetBG(RetainPtr<const CPDF_Object> pObject); + void SetUCR(RetainPtr<const CPDF_Object> pObject); + void SetHT(RetainPtr<const CPDF_Object> pObject); void SetFlatness(float flatness); void SetSmoothness(float smoothness); @@ -80,14 +82,13 @@ private: class StateData final : public Retainable { public: - template <typename T, typename... Args> - friend RetainPtr<T> pdfium::MakeRetain(Args&&... args); + CONSTRUCT_VIA_MAKE_RETAIN; RetainPtr<StateData> Clone() const; ByteString m_BlendMode = pdfium::transparency::kNormal; BlendMode m_BlendType = BlendMode::kNormal; - RetainPtr<CPDF_Object> m_pSoftMask; + RetainPtr<CPDF_Dictionary> m_pSoftMask; CFX_Matrix m_SMaskMatrix; float m_StrokeAlpha = 1.0f; float m_FillAlpha = 1.0f;
diff --git a/core/fpdfapi/page/cpdf_graphicstates.cpp b/core/fpdfapi/page/cpdf_graphicstates.cpp index 962bc0a..8f19a2d 100644 --- a/core/fpdfapi/page/cpdf_graphicstates.cpp +++ b/core/fpdfapi/page/cpdf_graphicstates.cpp
@@ -1,4 +1,4 @@ -// Copyright 2016 PDFium Authors. All rights reserved. +// Copyright 2016 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -6,9 +6,9 @@ #include "core/fpdfapi/page/cpdf_graphicstates.h" -CPDF_GraphicStates::CPDF_GraphicStates() {} +CPDF_GraphicStates::CPDF_GraphicStates() = default; -CPDF_GraphicStates::~CPDF_GraphicStates() {} +CPDF_GraphicStates::~CPDF_GraphicStates() = default; void CPDF_GraphicStates::DefaultStates() { m_ColorState.Emplace();
diff --git a/core/fpdfapi/page/cpdf_graphicstates.h b/core/fpdfapi/page/cpdf_graphicstates.h index b7e7fa2..9f604c7 100644 --- a/core/fpdfapi/page/cpdf_graphicstates.h +++ b/core/fpdfapi/page/cpdf_graphicstates.h
@@ -1,4 +1,4 @@ -// Copyright 2016 PDFium Authors. All rights reserved. +// Copyright 2016 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file.
diff --git a/core/fpdfapi/page/cpdf_iccprofile.cpp b/core/fpdfapi/page/cpdf_iccprofile.cpp index f8d40e4..82bbe9b 100644 --- a/core/fpdfapi/page/cpdf_iccprofile.cpp +++ b/core/fpdfapi/page/cpdf_iccprofile.cpp
@@ -1,4 +1,4 @@ -// Copyright 2017 PDFium Authors. All rights reserved. +// Copyright 2017 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -6,8 +6,10 @@ #include "core/fpdfapi/page/cpdf_iccprofile.h" +#include <utility> + #include "core/fpdfapi/parser/cpdf_stream.h" -#include "core/fxcodec/icc/iccmodule.h" +#include "core/fxcodec/icc/icc_transform.h" namespace { @@ -18,17 +20,32 @@ } // namespace -CPDF_IccProfile::CPDF_IccProfile(const CPDF_Stream* pStream, +CPDF_IccProfile::CPDF_IccProfile(RetainPtr<const CPDF_Stream> pStream, pdfium::span<const uint8_t> span) - : m_bsRGB(DetectSRGB(span)), m_pStream(pStream) { + : m_bsRGB(DetectSRGB(span)), m_pStream(std::move(pStream)) { if (m_bsRGB) { m_nSrcComponents = 3; return; } - m_Transform = IccModule::CreateTransformSRGB(span); + m_Transform = fxcodec::IccTransform::CreateTransformSRGB(span); if (m_Transform) m_nSrcComponents = m_Transform->components(); } CPDF_IccProfile::~CPDF_IccProfile() = default; + +bool CPDF_IccProfile::IsNormal() const { + return m_Transform->IsNormal(); +} + +void CPDF_IccProfile::Translate(pdfium::span<const float> pSrcValues, + pdfium::span<float> pDestValues) { + m_Transform->Translate(pSrcValues, pDestValues); +} + +void CPDF_IccProfile::TranslateScanline(pdfium::span<uint8_t> pDest, + pdfium::span<const uint8_t> pSrc, + int pixels) { + m_Transform->TranslateScanline(pDest, pSrc, pixels); +}
diff --git a/core/fpdfapi/page/cpdf_iccprofile.h b/core/fpdfapi/page/cpdf_iccprofile.h index 070f884..0e040aa 100644 --- a/core/fpdfapi/page/cpdf_iccprofile.h +++ b/core/fpdfapi/page/cpdf_iccprofile.h
@@ -1,4 +1,4 @@ -// Copyright 2017 PDFium Authors. All rights reserved. +// Copyright 2017 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -7,6 +7,8 @@ #ifndef CORE_FPDFAPI_PAGE_CPDF_ICCPROFILE_H_ #define CORE_FPDFAPI_PAGE_CPDF_ICCPROFILE_H_ +#include <stdint.h> + #include <memory> #include "core/fxcrt/observed_ptr.h" @@ -16,29 +18,35 @@ class CPDF_Stream; namespace fxcodec { -class CLcmsCmm; +class IccTransform; } // namespace fxcodec class CPDF_IccProfile final : public Retainable, public Observable { public: - template <typename T, typename... Args> - friend RetainPtr<T> pdfium::MakeRetain(Args&&... args); + CONSTRUCT_VIA_MAKE_RETAIN; - const CPDF_Stream* GetStream() const { return m_pStream.Get(); } bool IsValid() const { return IsSRGB() || IsSupported(); } bool IsSRGB() const { return m_bsRGB; } bool IsSupported() const { return !!m_Transform; } - fxcodec::CLcmsCmm* transform() { return m_Transform.get(); } uint32_t GetComponents() const { return m_nSrcComponents; } + bool IsNormal() const; + void Translate(pdfium::span<const float> pSrcValues, + pdfium::span<float> pDestValues); + void TranslateScanline(pdfium::span<uint8_t> pDest, + pdfium::span<const uint8_t> pSrc, + int pixels); + private: - CPDF_IccProfile(const CPDF_Stream* pStream, pdfium::span<const uint8_t> span); + // Keeps stream alive for the duration of the CPDF_IccProfile. + CPDF_IccProfile(RetainPtr<const CPDF_Stream> pStream, + pdfium::span<const uint8_t> span); ~CPDF_IccProfile() override; const bool m_bsRGB; uint32_t m_nSrcComponents = 0; - RetainPtr<const CPDF_Stream> const m_pStream; - std::unique_ptr<fxcodec::CLcmsCmm> m_Transform; + RetainPtr<const CPDF_Stream> const m_pStream; // Used by `m_Transform`. + std::unique_ptr<fxcodec::IccTransform> m_Transform; }; #endif // CORE_FPDFAPI_PAGE_CPDF_ICCPROFILE_H_
diff --git a/core/fpdfapi/page/cpdf_image.cpp b/core/fpdfapi/page/cpdf_image.cpp index ce46538..c9be231 100644 --- a/core/fpdfapi/page/cpdf_image.cpp +++ b/core/fpdfapi/page/cpdf_image.cpp
@@ -1,4 +1,4 @@ -// Copyright 2016 PDFium Authors. All rights reserved. +// Copyright 2016 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -6,14 +6,16 @@ #include "core/fpdfapi/page/cpdf_image.h" +#include <stdint.h> + #include <algorithm> #include <memory> #include <utility> -#include <vector> #include "constants/stream_dict_common.h" #include "core/fpdfapi/page/cpdf_dib.h" #include "core/fpdfapi/page/cpdf_page.h" +#include "core/fpdfapi/page/cpdf_pageimagecache.h" #include "core/fpdfapi/parser/cpdf_array.h" #include "core/fpdfapi/parser/cpdf_boolean.h" #include "core/fpdfapi/parser/cpdf_dictionary.h" @@ -23,14 +25,16 @@ #include "core/fpdfapi/parser/cpdf_reference.h" #include "core/fpdfapi/parser/cpdf_stream.h" #include "core/fpdfapi/parser/cpdf_string.h" -#include "core/fxcodec/fx_codec.h" #include "core/fxcodec/jpeg/jpegmodule.h" +#include "core/fxcrt/data_vector.h" +#include "core/fxcrt/fx_2d_size.h" #include "core/fxcrt/fx_memory_wrappers.h" #include "core/fxcrt/fx_stream.h" +#include "core/fxcrt/span_util.h" #include "core/fxge/dib/cfx_dibitmap.h" -#include "core/fxge/fx_dib.h" +#include "core/fxge/dib/fx_dib.h" +#include "third_party/base/check.h" #include "third_party/base/numerics/safe_conversions.h" -#include "third_party/base/ptr_util.h" // static bool CPDF_Image::IsValidJpegComponent(int32_t comps) { @@ -43,28 +47,29 @@ } CPDF_Image::CPDF_Image(CPDF_Document* pDoc) : m_pDocument(pDoc) { - ASSERT(m_pDocument); + DCHECK(m_pDocument); } CPDF_Image::CPDF_Image(CPDF_Document* pDoc, RetainPtr<CPDF_Stream> pStream) : m_bIsInline(true), m_pDocument(pDoc), m_pStream(std::move(pStream)) { - ASSERT(m_pDocument); - FinishInitialization(m_pStream->GetDict()); + DCHECK(m_pDocument); + FinishInitialization(); } CPDF_Image::CPDF_Image(CPDF_Document* pDoc, uint32_t dwStreamObjNum) : m_pDocument(pDoc), - m_pStream(ToStream(pDoc->GetIndirectObject(dwStreamObjNum))) { - ASSERT(m_pDocument); - FinishInitialization(m_pStream->GetDict()); + m_pStream(ToStream(pDoc->GetMutableIndirectObject(dwStreamObjNum))) { + DCHECK(m_pDocument); + FinishInitialization(); } CPDF_Image::~CPDF_Image() = default; -void CPDF_Image::FinishInitialization(CPDF_Dictionary* pStreamDict) { - m_pOC.Reset(pStreamDict->GetDictFor("OC")); +void CPDF_Image::FinishInitialization() { + RetainPtr<CPDF_Dictionary> pStreamDict = m_pStream->GetMutableDict(); + m_pOC = pStreamDict->GetMutableDictFor("OC"); m_bIsMask = !pStreamDict->KeyExist("ColorSpace") || - pStreamDict->GetIntegerFor("ImageMask"); + pStreamDict->GetBooleanFor("ImageMask", /*bDefault=*/false); m_bInterpolate = !!pStreamDict->GetIntegerFor("Interpolate"); m_Height = pStreamDict->GetIntegerFor("Height"); m_Width = pStreamDict->GetIntegerFor("Width"); @@ -77,18 +82,26 @@ m_pDocument->AddIndirectObject(m_pStream); } -CPDF_Dictionary* CPDF_Image::GetDict() const { +RetainPtr<const CPDF_Dictionary> CPDF_Image::GetDict() const { return m_pStream ? m_pStream->GetDict() : nullptr; } +RetainPtr<const CPDF_Stream> CPDF_Image::GetStream() const { + return m_pStream; +} + +RetainPtr<const CPDF_Dictionary> CPDF_Image::GetOC() const { + return m_pOC; +} + RetainPtr<CPDF_Dictionary> CPDF_Image::InitJPEG( pdfium::span<uint8_t> src_span) { - Optional<JpegModule::JpegImageInfo> info_opt = - fxcodec::ModuleMgr::GetInstance()->GetJpegModule()->LoadInfo(src_span); + absl::optional<JpegModule::ImageInfo> info_opt = + JpegModule::LoadInfo(src_span); if (!info_opt.has_value()) return nullptr; - const JpegModule::JpegImageInfo& info = info_opt.value(); + const JpegModule::ImageInfo& info = info_opt.value(); if (!IsValidJpegComponent(info.num_components) || !IsValidJpegBitsPerComponent(info.bits_per_components)) { return nullptr; @@ -103,17 +116,17 @@ csname = "DeviceRGB"; } else if (info.num_components == 4) { csname = "DeviceCMYK"; - CPDF_Array* pDecode = pDict->SetNewFor<CPDF_Array>("Decode"); + auto pDecode = pDict->SetNewFor<CPDF_Array>("Decode"); for (int n = 0; n < 4; n++) { - pDecode->AddNew<CPDF_Number>(1); - pDecode->AddNew<CPDF_Number>(0); + pDecode->AppendNew<CPDF_Number>(1); + pDecode->AppendNew<CPDF_Number>(0); } } pDict->SetNewFor<CPDF_Name>("ColorSpace", csname); pDict->SetNewFor<CPDF_Number>("BitsPerComponent", info.bits_per_components); pDict->SetNewFor<CPDF_Name>("Filter", "DCTDecode"); if (!info.color_transform) { - CPDF_Dictionary* pParms = + auto pParms = pDict->SetNewFor<CPDF_Dictionary>(pdfium::stream::kDecodeParms); pParms->SetNewFor<CPDF_Number>("ColorTransform", 0); } @@ -125,43 +138,43 @@ return pDict; } -void CPDF_Image::SetJpegImage(const RetainPtr<IFX_SeekableReadStream>& pFile) { +void CPDF_Image::SetJpegImage(RetainPtr<IFX_SeekableReadStream> pFile) { uint32_t size = pdfium::base::checked_cast<uint32_t>(pFile->GetSize()); if (!size) return; uint32_t dwEstimateSize = std::min(size, 8192U); - std::vector<uint8_t> data(dwEstimateSize); - if (!pFile->ReadBlockAtOffset(data.data(), 0, dwEstimateSize)) + DataVector<uint8_t> data(dwEstimateSize); + if (!pFile->ReadBlockAtOffset(data, 0)) return; RetainPtr<CPDF_Dictionary> pDict = InitJPEG(data); if (!pDict && size > dwEstimateSize) { data.resize(size); - if (pFile->ReadBlockAtOffset(data.data(), 0, size)) + if (pFile->ReadBlockAtOffset(data, 0)) pDict = InitJPEG(data); } if (!pDict) return; - m_pStream->InitStreamFromFile(pFile, std::move(pDict)); + m_pStream->InitStreamFromFile(std::move(pFile), std::move(pDict)); } -void CPDF_Image::SetJpegImageInline( - const RetainPtr<IFX_SeekableReadStream>& pFile) { +void CPDF_Image::SetJpegImageInline(RetainPtr<IFX_SeekableReadStream> pFile) { uint32_t size = pdfium::base::checked_cast<uint32_t>(pFile->GetSize()); if (!size) return; - std::vector<uint8_t> data(size); - if (!pFile->ReadBlockAtOffset(data.data(), 0, size)) + DataVector<uint8_t> data(size); + if (!pFile->ReadBlockAtOffset(data, 0)) return; RetainPtr<CPDF_Dictionary> pDict = InitJPEG(data); if (!pDict) return; - m_pStream->InitStream(data, std::move(pDict)); + m_pStream = + pdfium::MakeRetain<CPDF_Stream>(std::move(data), std::move(pDict)); } void CPDF_Image::SetImage(const RetainPtr<CFX_DIBitmap>& pBitmap) { @@ -184,7 +197,7 @@ int32_t set_r = 0; int32_t set_g = 0; int32_t set_b = 0; - if (!pBitmap->IsAlphaMask()) { + if (!pBitmap->IsMaskFormat()) { std::tie(reset_a, reset_r, reset_g, reset_b) = ArgbDecode(pBitmap->GetPaletteArgb(0)); std::tie(set_a, set_r, set_g, set_b) = @@ -193,15 +206,15 @@ if (set_a == 0 || reset_a == 0) { pDict->SetNewFor<CPDF_Boolean>("ImageMask", true); if (reset_a == 0) { - CPDF_Array* pArray = pDict->SetNewFor<CPDF_Array>("Decode"); - pArray->AddNew<CPDF_Number>(1); - pArray->AddNew<CPDF_Number>(0); + auto pArray = pDict->SetNewFor<CPDF_Array>("Decode"); + pArray->AppendNew<CPDF_Number>(1); + pArray->AppendNew<CPDF_Number>(0); } } else { - CPDF_Array* pCS = pDict->SetNewFor<CPDF_Array>("ColorSpace"); - pCS->AddNew<CPDF_Name>("Indexed"); - pCS->AddNew<CPDF_Name>("DeviceRGB"); - pCS->AddNew<CPDF_Number>(1); + auto pCS = pDict->SetNewFor<CPDF_Array>("ColorSpace"); + pCS->AppendNew<CPDF_Name>("Indexed"); + pCS->AppendNew<CPDF_Name>("DeviceRGB"); + pCS->AppendNew<CPDF_Number>(1); ByteString ct; { // Span's lifetime must end before ReleaseBuffer() below. @@ -214,33 +227,32 @@ pBuf[5] = static_cast<char>(set_b); } ct.ReleaseBuffer(6); - pCS->AddNew<CPDF_String>(ct, true); + pCS->AppendNew<CPDF_String>(ct, true); } pDict->SetNewFor<CPDF_Number>("BitsPerComponent", 1); dest_pitch = (BitmapWidth + 7) / 8; } else if (bpp == 8) { - size_t palette_size = pBitmap->GetPaletteSize(); + size_t palette_size = pBitmap->GetRequiredPaletteSize(); if (palette_size > 0) { - ASSERT(palette_size <= 256); - CPDF_Array* pCS = m_pDocument->NewIndirect<CPDF_Array>(); - pCS->AddNew<CPDF_Name>("Indexed"); - pCS->AddNew<CPDF_Name>("DeviceRGB"); - pCS->AddNew<CPDF_Number>(static_cast<int>(palette_size - 1)); - std::unique_ptr<uint8_t, FxFreeDeleter> pColorTable( - FX_Alloc2D(uint8_t, palette_size, 3)); - uint8_t* ptr = pColorTable.get(); + DCHECK(palette_size <= 256); + auto pCS = m_pDocument->NewIndirect<CPDF_Array>(); + pCS->AppendNew<CPDF_Name>("Indexed"); + pCS->AppendNew<CPDF_Name>("DeviceRGB"); + pCS->AppendNew<CPDF_Number>(static_cast<int>(palette_size - 1)); + DataVector<uint8_t> color_table(Fx2DSizeOrDie(palette_size, 3)); + auto color_table_span = pdfium::make_span(color_table); for (size_t i = 0; i < palette_size; i++) { uint32_t argb = pBitmap->GetPaletteArgb(i); - ptr[0] = FXARGB_R(argb); - ptr[1] = FXARGB_G(argb); - ptr[2] = FXARGB_B(argb); - ptr += 3; + color_table_span[0] = FXARGB_R(argb); + color_table_span[1] = FXARGB_G(argb); + color_table_span[2] = FXARGB_B(argb); + color_table_span = color_table_span.subspan(3); } auto pNewDict = m_pDocument->New<CPDF_Dictionary>(); - CPDF_Stream* pCTS = m_pDocument->NewIndirect<CPDF_Stream>( - std::move(pColorTable), palette_size * 3, std::move(pNewDict)); - pCS->AddNew<CPDF_Reference>(m_pDocument.Get(), pCTS->GetObjNum()); - pDict->SetNewFor<CPDF_Reference>("ColorSpace", m_pDocument.Get(), + auto pCTS = m_pDocument->NewIndirect<CPDF_Stream>(std::move(color_table), + std::move(pNewDict)); + pCS->AppendNew<CPDF_Reference>(m_pDocument, pCTS->GetObjNum()); + pDict->SetNewFor<CPDF_Reference>("ColorSpace", m_pDocument, pCS->GetObjNum()); } else { pDict->SetNewFor<CPDF_Name>("ColorSpace", "DeviceGray"); @@ -255,84 +267,78 @@ } RetainPtr<CFX_DIBitmap> pMaskBitmap; - if (pBitmap->HasAlpha()) + if (pBitmap->IsAlphaFormat()) pMaskBitmap = pBitmap->CloneAlphaMask(); if (pMaskBitmap) { - int32_t maskWidth = pMaskBitmap->GetWidth(); - int32_t maskHeight = pMaskBitmap->GetHeight(); - std::unique_ptr<uint8_t, FxFreeDeleter> mask_buf; - int32_t mask_size = 0; + const int32_t mask_width = pMaskBitmap->GetWidth(); + const int32_t mask_height = pMaskBitmap->GetHeight(); + DataVector<uint8_t> mask_buf; RetainPtr<CPDF_Dictionary> pMaskDict = - CreateXObjectImageDict(maskWidth, maskHeight); + CreateXObjectImageDict(mask_width, mask_height); pMaskDict->SetNewFor<CPDF_Name>("ColorSpace", "DeviceGray"); pMaskDict->SetNewFor<CPDF_Number>("BitsPerComponent", 8); - if (pMaskBitmap->GetFormat() != FXDIB_1bppMask) { - mask_buf.reset(FX_Alloc2D(uint8_t, maskHeight, maskWidth)); - mask_size = maskHeight * maskWidth; // Safe since checked alloc returned. - for (int32_t a = 0; a < maskHeight; a++) { - memcpy(mask_buf.get() + a * maskWidth, pMaskBitmap->GetScanline(a), - maskWidth); + if (pMaskBitmap->GetFormat() != FXDIB_Format::k1bppMask) { + mask_buf.resize(Fx2DSizeOrDie(mask_width, mask_height)); + for (int32_t a = 0; a < mask_height; a++) { + fxcrt::spancpy(pdfium::make_span(mask_buf).subspan(a * mask_width), + pMaskBitmap->GetScanline(a).first(mask_width)); } } - pMaskDict->SetNewFor<CPDF_Number>("Length", mask_size); - CPDF_Stream* pNewStream = m_pDocument->NewIndirect<CPDF_Stream>( - std::move(mask_buf), mask_size, std::move(pMaskDict)); - pDict->SetNewFor<CPDF_Reference>("SMask", m_pDocument.Get(), + pMaskDict->SetNewFor<CPDF_Number>( + "Length", pdfium::base::checked_cast<int>(mask_buf.size())); + auto pNewStream = m_pDocument->NewIndirect<CPDF_Stream>( + std::move(mask_buf), std::move(pMaskDict)); + pDict->SetNewFor<CPDF_Reference>("SMask", m_pDocument, pNewStream->GetObjNum()); } - uint8_t* src_buf = pBitmap->GetBuffer(); - int32_t src_pitch = pBitmap->GetPitch(); - std::unique_ptr<uint8_t, FxFreeDeleter> dest_buf( - FX_Alloc2D(uint8_t, dest_pitch, BitmapHeight)); - // Safe as checked alloc returned. - size_t dest_size = dest_pitch * BitmapHeight; - auto dest_span = pdfium::make_span(dest_buf.get(), dest_size); - size_t dest_span_offset = 0; + DataVector<uint8_t> dest_buf(Fx2DSizeOrDie(dest_pitch, BitmapHeight)); + pdfium::span<uint8_t> dest_span = pdfium::make_span(dest_buf); + pdfium::span<const uint8_t> src_span = pBitmap->GetBuffer(); + const int32_t src_pitch = pBitmap->GetPitch(); if (bCopyWithoutAlpha) { for (int32_t i = 0; i < BitmapHeight; i++) { - memcpy(&dest_span[dest_span_offset], src_buf, dest_pitch); - dest_span_offset += dest_pitch; - src_buf += src_pitch; + fxcrt::spancpy(dest_span, src_span.first(dest_pitch)); + dest_span = dest_span.subspan(dest_pitch); + src_span = src_span.subspan(src_pitch); } } else { - int32_t src_offset = 0; + const size_t src_step = bpp == 24 ? 3 : 4; for (int32_t row = 0; row < BitmapHeight; row++) { - size_t dest_span_row_offset = dest_span_offset; - src_offset = row * src_pitch; + uint8_t* dest_ptr = dest_span.data(); + const uint8_t* src_ptr = src_span.data(); for (int32_t column = 0; column < BitmapWidth; column++) { - float alpha = 1; - dest_span[dest_span_row_offset] = - static_cast<uint8_t>(src_buf[src_offset + 2] * alpha); - dest_span[dest_span_row_offset + 1] = - static_cast<uint8_t>(src_buf[src_offset + 1] * alpha); - dest_span[dest_span_row_offset + 2] = - static_cast<uint8_t>(src_buf[src_offset] * alpha); - dest_span_row_offset += 3; - src_offset += bpp == 24 ? 3 : 4; + dest_ptr[0] = src_ptr[2]; + dest_ptr[1] = src_ptr[1]; + dest_ptr[2] = src_ptr[0]; + dest_ptr += 3; + src_ptr += src_step; } - - dest_span_offset += dest_pitch; + dest_span = dest_span.subspan(dest_pitch); + src_span = src_span.subspan(src_pitch); } } - if (!m_pStream) - m_pStream = pdfium::MakeRetain<CPDF_Stream>(); - m_pStream->InitStream(dest_span, std::move(pDict)); - m_bIsMask = pBitmap->IsAlphaMask(); + m_pStream = + pdfium::MakeRetain<CPDF_Stream>(std::move(dest_buf), std::move(pDict)); + m_bIsMask = pBitmap->IsMaskFormat(); m_Width = BitmapWidth; m_Height = BitmapHeight; } void CPDF_Image::ResetCache(CPDF_Page* pPage) { RetainPtr<CPDF_Image> pHolder(this); - pPage->GetRenderCache()->ResetBitmapForImage(pHolder); + pPage->GetPageImageCache()->ResetBitmapForImage(std::move(pHolder)); +} + +RetainPtr<CPDF_DIB> CPDF_Image::CreateNewDIB() const { + return pdfium::MakeRetain<CPDF_DIB>(GetDocument(), GetStream()); } RetainPtr<CFX_DIBBase> CPDF_Image::LoadDIBBase() const { - auto source = pdfium::MakeRetain<CPDF_DIB>(); - if (!source->Load(m_pDocument.Get(), m_pStream.Get())) + RetainPtr<CPDF_DIB> source = CreateNewDIB(); + if (!source->Load()) return nullptr; if (!source->IsJBigImage()) @@ -353,14 +359,15 @@ } bool CPDF_Image::StartLoadDIBBase(const CPDF_Dictionary* pFormResource, - CPDF_Dictionary* pPageResource, + const CPDF_Dictionary* pPageResource, bool bStdCS, - uint32_t GroupFamily, - bool bLoadMask) { - auto source = pdfium::MakeRetain<CPDF_DIB>(); - CPDF_DIB::LoadState ret = source->StartLoadDIBBase( - m_pDocument.Get(), m_pStream.Get(), true, pFormResource, pPageResource, - bStdCS, GroupFamily, bLoadMask); + CPDF_ColorSpace::Family GroupFamily, + bool bLoadMask, + const CFX_Size& max_size_required) { + RetainPtr<CPDF_DIB> source = CreateNewDIB(); + CPDF_DIB::LoadState ret = + source->StartLoadDIBBase(true, pFormResource, pPageResource, bStdCS, + GroupFamily, bLoadMask, max_size_required); if (ret == CPDF_DIB::LoadState::kFail) { m_pDIBBase.Reset(); return false;
diff --git a/core/fpdfapi/page/cpdf_image.h b/core/fpdfapi/page/cpdf_image.h index 4194d49..04355a9 100644 --- a/core/fpdfapi/page/cpdf_image.h +++ b/core/fpdfapi/page/cpdf_image.h
@@ -1,4 +1,4 @@ -// Copyright 2016 PDFium Authors. All rights reserved. +// Copyright 2016 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -7,15 +7,16 @@ #ifndef CORE_FPDFAPI_PAGE_CPDF_IMAGE_H_ #define CORE_FPDFAPI_PAGE_CPDF_IMAGE_H_ -#include <memory> +#include <stdint.h> -#include "core/fxcrt/fx_system.h" +#include "core/fpdfapi/page/cpdf_colorspace.h" #include "core/fxcrt/retain_ptr.h" #include "core/fxcrt/unowned_ptr.h" #include "third_party/base/span.h" class CFX_DIBBase; class CFX_DIBitmap; +class CPDF_DIB; class CPDF_Dictionary; class CPDF_Document; class CPDF_Page; @@ -25,40 +26,41 @@ class CPDF_Image final : public Retainable { public: - template <typename T, typename... Args> - friend RetainPtr<T> pdfium::MakeRetain(Args&&... args); + CONSTRUCT_VIA_MAKE_RETAIN; static bool IsValidJpegComponent(int32_t comps); static bool IsValidJpegBitsPerComponent(int32_t bpc); void ConvertStreamToIndirectObject(); - CPDF_Dictionary* GetDict() const; - CPDF_Stream* GetStream() const { return m_pStream.Get(); } - const CPDF_Dictionary* GetOC() const { return m_pOC.Get(); } - CPDF_Document* GetDocument() const { return m_pDocument.Get(); } + RetainPtr<const CPDF_Dictionary> GetDict() const; + RetainPtr<const CPDF_Stream> GetStream() const; + RetainPtr<const CPDF_Dictionary> GetOC() const; + CPDF_Document* GetDocument() const { return m_pDocument; } int32_t GetPixelHeight() const { return m_Height; } int32_t GetPixelWidth() const { return m_Width; } - + uint32_t GetMatteColor() const { return m_MatteColor; } bool IsInline() const { return m_bIsInline; } bool IsMask() const { return m_bIsMask; } bool IsInterpol() const { return m_bInterpolate; } + RetainPtr<CPDF_DIB> CreateNewDIB() const; RetainPtr<CFX_DIBBase> LoadDIBBase() const; void SetImage(const RetainPtr<CFX_DIBitmap>& pBitmap); - void SetJpegImage(const RetainPtr<IFX_SeekableReadStream>& pFile); - void SetJpegImageInline(const RetainPtr<IFX_SeekableReadStream>& pFile); + void SetJpegImage(RetainPtr<IFX_SeekableReadStream> pFile); + void SetJpegImageInline(RetainPtr<IFX_SeekableReadStream> pFile); void ResetCache(CPDF_Page* pPage); // Returns whether to Continue() or not. bool StartLoadDIBBase(const CPDF_Dictionary* pFormResource, - CPDF_Dictionary* pPageResource, + const CPDF_Dictionary* pPageResource, bool bStdCS, - uint32_t GroupFamily, - bool bLoadMask); + CPDF_ColorSpace::Family GroupFamily, + bool bLoadMask, + const CFX_Size& max_size_required); // Returns whether to Continue() or not. bool Continue(PauseIndicatorIface* pPause); @@ -66,27 +68,25 @@ RetainPtr<CFX_DIBBase> DetachBitmap(); RetainPtr<CFX_DIBBase> DetachMask(); - RetainPtr<CFX_DIBBase> m_pDIBBase; - RetainPtr<CFX_DIBBase> m_pMask; - uint32_t m_MatteColor = 0; - private: explicit CPDF_Image(CPDF_Document* pDoc); CPDF_Image(CPDF_Document* pDoc, RetainPtr<CPDF_Stream> pStream); CPDF_Image(CPDF_Document* pDoc, uint32_t dwStreamObjNum); ~CPDF_Image() override; - void FinishInitialization(CPDF_Dictionary* pStreamDict); + void FinishInitialization(); RetainPtr<CPDF_Dictionary> InitJPEG(pdfium::span<uint8_t> src_span); - RetainPtr<CPDF_Dictionary> CreateXObjectImageDict(int width, int height); int32_t m_Height = 0; int32_t m_Width = 0; + uint32_t m_MatteColor = 0; bool m_bIsInline = false; bool m_bIsMask = false; bool m_bInterpolate = false; UnownedPtr<CPDF_Document> const m_pDocument; + RetainPtr<CFX_DIBBase> m_pDIBBase; + RetainPtr<CFX_DIBBase> m_pMask; RetainPtr<CPDF_Stream> m_pStream; RetainPtr<const CPDF_Dictionary> m_pOC; };
diff --git a/core/fpdfapi/page/cpdf_imageloader.cpp b/core/fpdfapi/page/cpdf_imageloader.cpp new file mode 100644 index 0000000..78f4f1f --- /dev/null +++ b/core/fpdfapi/page/cpdf_imageloader.cpp
@@ -0,0 +1,80 @@ +// Copyright 2016 The PDFium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com + +#include "core/fpdfapi/page/cpdf_imageloader.h" + +#include <utility> + +#include "core/fpdfapi/page/cpdf_dib.h" +#include "core/fpdfapi/page/cpdf_image.h" +#include "core/fpdfapi/page/cpdf_imageobject.h" +#include "core/fpdfapi/page/cpdf_pageimagecache.h" +#include "core/fpdfapi/page/cpdf_transferfunc.h" +#include "core/fxge/dib/cfx_dibitmap.h" +#include "third_party/base/check.h" + +CPDF_ImageLoader::CPDF_ImageLoader() = default; + +CPDF_ImageLoader::~CPDF_ImageLoader() = default; + +bool CPDF_ImageLoader::Start(const CPDF_ImageObject* pImage, + CPDF_PageImageCache* pPageImageCache, + const CPDF_Dictionary* pFormResource, + const CPDF_Dictionary* pPageResource, + bool bStdCS, + CPDF_ColorSpace::Family eFamily, + bool bLoadMask, + const CFX_Size& max_size_required) { + m_pCache = pPageImageCache; + m_pImageObject = pImage; + bool ret; + if (m_pCache) { + ret = m_pCache->StartGetCachedBitmap(m_pImageObject->GetImage(), + pFormResource, pPageResource, bStdCS, + eFamily, bLoadMask, max_size_required); + } else { + ret = m_pImageObject->GetImage()->StartLoadDIBBase( + pFormResource, pPageResource, bStdCS, eFamily, bLoadMask, + max_size_required); + } + if (!ret) + HandleFailure(); + return ret; +} + +bool CPDF_ImageLoader::Continue(PauseIndicatorIface* pPause) { + bool ret = m_pCache ? m_pCache->Continue(pPause) + : m_pImageObject->GetImage()->Continue(pPause); + if (!ret) + HandleFailure(); + return ret; +} + +RetainPtr<CFX_DIBBase> CPDF_ImageLoader::TranslateImage( + RetainPtr<CPDF_TransferFunc> pTransferFunc) { + DCHECK(pTransferFunc); + DCHECK(!pTransferFunc->GetIdentity()); + m_pBitmap = pTransferFunc->TranslateImage(std::move(m_pBitmap)); + if (m_bCached && m_pMask) + m_pMask = m_pMask->Realize(); + m_bCached = false; + return m_pBitmap; +} + +void CPDF_ImageLoader::HandleFailure() { + if (m_pCache) { + m_bCached = true; + m_pBitmap = m_pCache->DetachCurBitmap(); + m_pMask = m_pCache->DetachCurMask(); + m_MatteColor = m_pCache->GetCurMatteColor(); + return; + } + RetainPtr<CPDF_Image> pImage = m_pImageObject->GetImage(); + m_bCached = false; + m_pBitmap = pImage->DetachBitmap(); + m_pMask = pImage->DetachMask(); + m_MatteColor = pImage->GetMatteColor(); +}
diff --git a/core/fpdfapi/page/cpdf_imageloader.h b/core/fpdfapi/page/cpdf_imageloader.h new file mode 100644 index 0000000..b0fcfb9 --- /dev/null +++ b/core/fpdfapi/page/cpdf_imageloader.h
@@ -0,0 +1,54 @@ +// Copyright 2016 The PDFium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com + +#ifndef CORE_FPDFAPI_PAGE_CPDF_IMAGELOADER_H_ +#define CORE_FPDFAPI_PAGE_CPDF_IMAGELOADER_H_ + +#include "core/fpdfapi/page/cpdf_colorspace.h" +#include "core/fxcrt/retain_ptr.h" +#include "core/fxcrt/unowned_ptr.h" + +class CFX_DIBBase; +class CPDF_Dictionary; +class CPDF_ImageObject; +class CPDF_PageImageCache; +class CPDF_TransferFunc; +class PauseIndicatorIface; + +class CPDF_ImageLoader { + public: + CPDF_ImageLoader(); + ~CPDF_ImageLoader(); + + bool Start(const CPDF_ImageObject* pImage, + CPDF_PageImageCache* pPageImageCache, + const CPDF_Dictionary* pFormResource, + const CPDF_Dictionary* pPageResource, + bool bStdCS, + CPDF_ColorSpace::Family eFamily, + bool bLoadMask, + const CFX_Size& max_size_required); + bool Continue(PauseIndicatorIface* pPause); + + RetainPtr<CFX_DIBBase> TranslateImage( + RetainPtr<CPDF_TransferFunc> pTransferFunc); + + const RetainPtr<CFX_DIBBase>& GetBitmap() const { return m_pBitmap; } + const RetainPtr<CFX_DIBBase>& GetMask() const { return m_pMask; } + uint32_t MatteColor() const { return m_MatteColor; } + + private: + void HandleFailure(); + + uint32_t m_MatteColor = 0; + bool m_bCached = false; + RetainPtr<CFX_DIBBase> m_pBitmap; + RetainPtr<CFX_DIBBase> m_pMask; + UnownedPtr<CPDF_PageImageCache> m_pCache; + UnownedPtr<const CPDF_ImageObject> m_pImageObject; +}; + +#endif // CORE_FPDFAPI_PAGE_CPDF_IMAGELOADER_H_
diff --git a/core/fpdfapi/page/cpdf_imageobject.cpp b/core/fpdfapi/page/cpdf_imageobject.cpp index 0f6a26b..c031502 100644 --- a/core/fpdfapi/page/cpdf_imageobject.cpp +++ b/core/fpdfapi/page/cpdf_imageobject.cpp
@@ -1,4 +1,4 @@ -// Copyright 2016 PDFium Authors. All rights reserved. +// Copyright 2016 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -6,12 +6,12 @@ #include "core/fpdfapi/page/cpdf_imageobject.h" -#include <memory> +#include <utility> #include "core/fpdfapi/page/cpdf_docpagedata.h" #include "core/fpdfapi/page/cpdf_image.h" -#include "core/fpdfapi/parser/cpdf_document.h" #include "core/fpdfapi/parser/cpdf_stream.h" +#include "core/fxcrt/fx_coordinates.h" #include "core/fxge/dib/cfx_dibbase.h" #include "core/fxge/dib/cfx_dibitmap.h" @@ -25,7 +25,7 @@ } CPDF_PageObject::Type CPDF_ImageObject::GetType() const { - return IMAGE; + return Type::kImage; } void CPDF_ImageObject::Transform(const CFX_Matrix& matrix) { @@ -48,12 +48,13 @@ void CPDF_ImageObject::CalcBoundingBox() { static constexpr CFX_FloatRect kRect(0.0f, 0.0f, 1.0f, 1.0f); + SetOriginalRect(kRect); SetRect(m_Matrix.TransformRect(kRect)); } -void CPDF_ImageObject::SetImage(const RetainPtr<CPDF_Image>& pImage) { +void CPDF_ImageObject::SetImage(RetainPtr<CPDF_Image> pImage) { MaybePurgeCache(); - m_pImage = pImage; + m_pImage = std::move(pImage); } RetainPtr<CPDF_Image> CPDF_ImageObject::GetImage() const { @@ -63,23 +64,29 @@ RetainPtr<CFX_DIBitmap> CPDF_ImageObject::GetIndependentBitmap() const { RetainPtr<CFX_DIBBase> pSource = GetImage()->LoadDIBBase(); - // Clone() is non-virtual, and can't be overloaded by CPDF_DIB to - // return a clone of the subclass as one would typically expect from a - // such a method. Instead, it only clones the CFX_DIBBase, none of whose - // members point to objects owned by |this| or the form containing |this|. - // As a result, the clone may outlive them. - return pSource ? pSource->Clone(nullptr) : nullptr; + // Realize() is non-virtual, and can't be overloaded by CPDF_DIB to + // return a full-up CPDF_DIB subclass. Instead, it only works upon the + // CFX_DIBBase, which is convenient since none of its members point to + // objects owned by |this| or the form containing |this|. As a result, + // the new bitmap may outlive them, giving the "independent" property + // this method is named after. + return pSource ? pSource->Realize() : nullptr; +} + +void CPDF_ImageObject::SetImageMatrix(const CFX_Matrix& matrix) { + m_Matrix = matrix; + CalcBoundingBox(); } void CPDF_ImageObject::MaybePurgeCache() { if (!m_pImage) return; - auto* pPageData = CPDF_DocPageData::FromDocument(m_pImage->GetDocument()); - if (!pPageData) + auto* pDoc = m_pImage->GetDocument(); + if (!pDoc) return; - CPDF_Stream* pStream = m_pImage->GetStream(); + RetainPtr<const CPDF_Stream> pStream = m_pImage->GetStream(); if (!pStream) return; @@ -88,5 +95,5 @@ return; m_pImage.Reset(); // Clear my reference before asking the cache. - pPageData->MaybePurgeImage(objnum); + pDoc->MaybePurgeImage(objnum); }
diff --git a/core/fpdfapi/page/cpdf_imageobject.h b/core/fpdfapi/page/cpdf_imageobject.h index f221a98..06e5a64 100644 --- a/core/fpdfapi/page/cpdf_imageobject.h +++ b/core/fpdfapi/page/cpdf_imageobject.h
@@ -1,4 +1,4 @@ -// Copyright 2016 PDFium Authors. All rights reserved. +// Copyright 2016 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -28,11 +28,11 @@ const CPDF_ImageObject* AsImage() const override; void CalcBoundingBox(); - void SetImage(const RetainPtr<CPDF_Image>& pImage); + void SetImage(RetainPtr<CPDF_Image> pImage); RetainPtr<CPDF_Image> GetImage() const; RetainPtr<CFX_DIBitmap> GetIndependentBitmap() const; - void set_matrix(const CFX_Matrix& matrix) { m_Matrix = matrix; } + void SetImageMatrix(const CFX_Matrix& matrix); const CFX_Matrix& matrix() const { return m_Matrix; } private:
diff --git a/core/fpdfapi/page/cpdf_indexedcs.cpp b/core/fpdfapi/page/cpdf_indexedcs.cpp new file mode 100644 index 0000000..85f694f --- /dev/null +++ b/core/fpdfapi/page/cpdf_indexedcs.cpp
@@ -0,0 +1,109 @@ +// Copyright 2022 The PDFium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "core/fpdfapi/page/cpdf_indexedcs.h" + +#include <set> +#include <vector> + +#include "core/fpdfapi/page/cpdf_colorspace.h" +#include "core/fpdfapi/page/cpdf_docpagedata.h" +#include "core/fpdfapi/parser/cpdf_array.h" +#include "core/fpdfapi/parser/cpdf_document.h" +#include "core/fpdfapi/parser/cpdf_object.h" +#include "core/fpdfapi/parser/cpdf_stream.h" +#include "core/fpdfapi/parser/cpdf_stream_acc.h" +#include "core/fpdfapi/parser/cpdf_string.h" +#include "core/fxcrt/data_vector.h" +#include "core/fxcrt/fx_2d_size.h" +#include "core/fxcrt/fx_safe_types.h" +#include "core/fxcrt/retain_ptr.h" +#include "third_party/base/check_op.h" +#include "third_party/base/span.h" + +CPDF_IndexedCS::CPDF_IndexedCS() : CPDF_BasedCS(Family::kIndexed) {} + +CPDF_IndexedCS::~CPDF_IndexedCS() = default; + +const CPDF_IndexedCS* CPDF_IndexedCS::AsIndexedCS() const { + return this; +} + +uint32_t CPDF_IndexedCS::v_Load(CPDF_Document* pDoc, + const CPDF_Array* pArray, + std::set<const CPDF_Object*>* pVisited) { + if (pArray->size() < 4) + return 0; + + RetainPtr<const CPDF_Object> pBaseObj = pArray->GetDirectObjectAt(1); + if (HasSameArray(pBaseObj.Get())) + return 0; + + auto* pDocPageData = CPDF_DocPageData::FromDocument(pDoc); + m_pBaseCS = + pDocPageData->GetColorSpaceGuarded(pBaseObj.Get(), nullptr, pVisited); + if (!m_pBaseCS) + return 0; + + // The base color space cannot be a Pattern or Indexed space, according to the + // PDF 1.7 spec, page 263. + Family family = m_pBaseCS->GetFamily(); + if (family == Family::kIndexed || family == Family::kPattern) + return 0; + + m_nBaseComponents = m_pBaseCS->CountComponents(); + DCHECK(m_nBaseComponents); + m_pCompMinMax = DataVector<float>(Fx2DSizeOrDie(m_nBaseComponents, 2)); + float defvalue; + for (uint32_t i = 0; i < m_nBaseComponents; i++) { + m_pBaseCS->GetDefaultValue(i, &defvalue, &m_pCompMinMax[i * 2], + &m_pCompMinMax[i * 2 + 1]); + m_pCompMinMax[i * 2 + 1] -= m_pCompMinMax[i * 2]; + } + m_MaxIndex = pArray->GetIntegerAt(2); + + RetainPtr<const CPDF_Object> pTableObj = pArray->GetDirectObjectAt(3); + if (!pTableObj) + return 0; + + if (const CPDF_String* pString = pTableObj->AsString()) { + m_Table = pString->GetString(); + } else if (const CPDF_Stream* pStream = pTableObj->AsStream()) { + auto pAcc = pdfium::MakeRetain<CPDF_StreamAcc>(pdfium::WrapRetain(pStream)); + pAcc->LoadAllDataFiltered(); + m_Table = ByteStringView(pAcc->GetSpan()); + } + return 1; +} + +bool CPDF_IndexedCS::GetRGB(pdfium::span<const float> pBuf, + float* R, + float* G, + float* B) const { + int32_t index = static_cast<int32_t>(pBuf[0]); + if (index < 0 || index > m_MaxIndex) + return false; + + DCHECK(m_nBaseComponents); + DCHECK_EQ(m_nBaseComponents, m_pBaseCS->CountComponents()); + + FX_SAFE_SIZE_T length = index; + length += 1; + length *= m_nBaseComponents; + if (!length.IsValid() || length.ValueOrDie() > m_Table.GetLength()) { + *R = 0; + *G = 0; + *B = 0; + return false; + } + + std::vector<float> comps(m_nBaseComponents); + const uint8_t* pTable = m_Table.raw_str(); + for (uint32_t i = 0; i < m_nBaseComponents; ++i) { + comps[i] = + m_pCompMinMax[i * 2] + + m_pCompMinMax[i * 2 + 1] * pTable[index * m_nBaseComponents + i] / 255; + } + return m_pBaseCS->GetRGB(comps, R, G, B); +}
diff --git a/core/fpdfapi/page/cpdf_indexedcs.h b/core/fpdfapi/page/cpdf_indexedcs.h new file mode 100644 index 0000000..325501f --- /dev/null +++ b/core/fpdfapi/page/cpdf_indexedcs.h
@@ -0,0 +1,43 @@ +// Copyright 2022 The PDFium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CORE_FPDFAPI_PAGE_CPDF_INDEXEDCS_H_ +#define CORE_FPDFAPI_PAGE_CPDF_INDEXEDCS_H_ + +#include <set> + +#include "core/fpdfapi/page/cpdf_basedcs.h" +#include "core/fxcrt/bytestring.h" +#include "core/fxcrt/data_vector.h" +#include "core/fxcrt/retain_ptr.h" + +class CPDF_Document; + +class CPDF_IndexedCS final : public CPDF_BasedCS { + public: + CONSTRUCT_VIA_MAKE_RETAIN; + ~CPDF_IndexedCS() override; + + // CPDF_ColorSpace: + bool GetRGB(pdfium::span<const float> pBuf, + float* R, + float* G, + float* B) const override; + const CPDF_IndexedCS* AsIndexedCS() const override; + uint32_t v_Load(CPDF_Document* pDoc, + const CPDF_Array* pArray, + std::set<const CPDF_Object*>* pVisited) override; + + int GetMaxIndex() const { return m_MaxIndex; } + + private: + CPDF_IndexedCS(); + + uint32_t m_nBaseComponents = 0; + int m_MaxIndex = 0; + ByteString m_Table; + DataVector<float> m_pCompMinMax; +}; + +#endif // CORE_FPDFAPI_PAGE_CPDF_INDEXEDCS_H_
diff --git a/core/fpdfapi/page/cpdf_meshstream.cpp b/core/fpdfapi/page/cpdf_meshstream.cpp index 06b2329..95f560f 100644 --- a/core/fpdfapi/page/cpdf_meshstream.cpp +++ b/core/fpdfapi/page/cpdf_meshstream.cpp
@@ -1,4 +1,4 @@ -// Copyright 2016 PDFium Authors. All rights reserved. +// Copyright 2016 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -6,13 +6,16 @@ #include "core/fpdfapi/page/cpdf_meshstream.h" +#include <utility> + #include "core/fpdfapi/page/cpdf_colorspace.h" #include "core/fpdfapi/page/cpdf_function.h" #include "core/fpdfapi/parser/cpdf_array.h" #include "core/fpdfapi/parser/cpdf_dictionary.h" #include "core/fpdfapi/parser/cpdf_stream.h" #include "core/fpdfapi/parser/cpdf_stream_acc.h" -#include "third_party/base/ptr_util.h" +#include "core/fxcrt/cfx_bitstream.h" +#include "third_party/base/check.h" #include "third_party/base/span.h" namespace { @@ -97,33 +100,21 @@ CPDF_MeshStream::CPDF_MeshStream( ShadingType type, const std::vector<std::unique_ptr<CPDF_Function>>& funcs, - const CPDF_Stream* pShadingStream, - const RetainPtr<CPDF_ColorSpace>& pCS) + RetainPtr<const CPDF_Stream> pShadingStream, + RetainPtr<CPDF_ColorSpace> pCS) : m_type(type), m_funcs(funcs), - m_pShadingStream(pShadingStream), - m_pCS(pCS), - m_nCoordBits(0), - m_nComponentBits(0), - m_nFlagBits(0), - m_nComponents(0), - m_CoordMax(0), - m_ComponentMax(0), - m_xmin(0), - m_xmax(0), - m_ymin(0), - m_ymax(0), - m_pStream(pdfium::MakeRetain<CPDF_StreamAcc>(pShadingStream)) { - memset(&m_ColorMin, 0, sizeof(m_ColorMin)); - memset(&m_ColorMax, 0, sizeof(m_ColorMax)); -} + m_pShadingStream(std::move(pShadingStream)), + m_pCS(std::move(pCS)), + m_pStream(pdfium::MakeRetain<CPDF_StreamAcc>(m_pShadingStream)) {} -CPDF_MeshStream::~CPDF_MeshStream() {} +CPDF_MeshStream::~CPDF_MeshStream() = default; bool CPDF_MeshStream::Load() { m_pStream->LoadAllDataFiltered(); - m_BitStream = pdfium::MakeUnique<CFX_BitStream>(m_pStream->GetSpan()); - const CPDF_Dictionary* pDict = m_pShadingStream->GetDict(); + m_BitStream = std::make_unique<CFX_BitStream>(m_pStream->GetSpan()); + + RetainPtr<const CPDF_Dictionary> pDict = m_pShadingStream->GetDict(); m_nCoordBits = pDict->GetIntegerFor("BitsPerCoordinate"); m_nComponentBits = pDict->GetIntegerFor("BitsPerComponent"); if (ShouldCheckBPC(m_type)) { @@ -142,17 +133,17 @@ return false; m_nComponents = m_funcs.empty() ? nComponents : 1; - const CPDF_Array* pDecode = pDict->GetArrayFor("Decode"); + RetainPtr<const CPDF_Array> pDecode = pDict->GetArrayFor("Decode"); if (!pDecode || pDecode->size() != 4 + m_nComponents * 2) return false; - m_xmin = pDecode->GetNumberAt(0); - m_xmax = pDecode->GetNumberAt(1); - m_ymin = pDecode->GetNumberAt(2); - m_ymax = pDecode->GetNumberAt(3); + m_xmin = pDecode->GetFloatAt(0); + m_xmax = pDecode->GetFloatAt(1); + m_ymin = pDecode->GetFloatAt(2); + m_ymax = pDecode->GetFloatAt(3); for (uint32_t i = 0; i < m_nComponents; ++i) { - m_ColorMin[i] = pDecode->GetNumberAt(i * 2 + 4); - m_ColorMax[i] = pDecode->GetNumberAt(i * 2 + 5); + m_ColorMin[i] = pDecode->GetFloatAt(i * 2 + 4); + m_ColorMax[i] = pDecode->GetFloatAt(i * 2 + 5); } if (ShouldCheckBPC(m_type)) { @@ -162,6 +153,18 @@ return true; } +void CPDF_MeshStream::SkipBits(uint32_t nbits) { + m_BitStream->SkipBits(nbits); +} + +void CPDF_MeshStream::ByteAlign() { + m_BitStream->ByteAlign(); +} + +bool CPDF_MeshStream::IsEOF() const { + return m_BitStream->IsEOF(); +} + bool CPDF_MeshStream::CanReadFlag() const { return m_BitStream->BitsRemaining() >= m_nFlagBits; } @@ -175,12 +178,12 @@ } uint32_t CPDF_MeshStream::ReadFlag() { - ASSERT(ShouldCheckBitsPerFlag(m_type)); + DCHECK(ShouldCheckBitsPerFlag(m_type)); return m_BitStream->GetBits(m_nFlagBits) & 0x03; } CFX_PointF CPDF_MeshStream::ReadCoords() { - ASSERT(ShouldCheckBPC(m_type)); + DCHECK(ShouldCheckBPC(m_type)); CFX_PointF pos; if (m_nCoordBits == 32) { @@ -198,7 +201,7 @@ } std::tuple<float, float, float> CPDF_MeshStream::ReadColor() { - ASSERT(ShouldCheckBPC(m_type)); + DCHECK(ShouldCheckBPC(m_type)); float color_value[kMaxComponents]; for (uint32_t i = 0; i < m_nComponents; ++i) { @@ -215,12 +218,10 @@ return std::tuple<float, float, float>(r, g, b); } - float result[kMaxComponents]; - memset(result, 0, sizeof(result)); - int nResults; + float result[kMaxComponents] = {}; for (const auto& func : m_funcs) { if (func && func->CountOutputs() <= kMaxComponents) - func->Call(color_value, 1, result, &nResults); + func->Call(pdfium::make_span(color_value, 1), result); } m_pCS->GetRGB(result, &r, &g, &b); @@ -253,7 +254,7 @@ if (m_BitStream->IsEOF() || !CanReadCoords()) return std::vector<CPDF_MeshVertex>(); - vertices.push_back(CPDF_MeshVertex()); + vertices.emplace_back(); CPDF_MeshVertex& vertex = vertices.back(); vertex.position = pObject2Bitmap.Transform(ReadCoords()); if (!CanReadColor())
diff --git a/core/fpdfapi/page/cpdf_meshstream.h b/core/fpdfapi/page/cpdf_meshstream.h index 939b192..b1dab6e 100644 --- a/core/fpdfapi/page/cpdf_meshstream.h +++ b/core/fpdfapi/page/cpdf_meshstream.h
@@ -1,4 +1,4 @@ -// Copyright 2016 PDFium Authors. All rights reserved. +// Copyright 2016 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -7,13 +7,13 @@ #ifndef CORE_FPDFAPI_PAGE_CPDF_MESHSTREAM_H_ #define CORE_FPDFAPI_PAGE_CPDF_MESHSTREAM_H_ +#include <stdint.h> + #include <memory> #include <tuple> #include <vector> #include "core/fpdfapi/page/cpdf_shadingpattern.h" -#include "core/fxcrt/cfx_bitstream.h" -#include "core/fxcrt/fx_system.h" #include "core/fxcrt/retain_ptr.h" class CPDF_StreamAcc; @@ -25,11 +25,12 @@ ~CPDF_MeshVertex(); CFX_PointF position; - float r; - float g; - float b; + float r = 0.0f; + float g = 0.0f; + float b = 0.0f; }; +class CFX_BitStream; class CFX_Matrix; class CPDF_ColorSpace; class CPDF_Function; @@ -39,12 +40,15 @@ public: CPDF_MeshStream(ShadingType type, const std::vector<std::unique_ptr<CPDF_Function>>& funcs, - const CPDF_Stream* pShadingStream, - const RetainPtr<CPDF_ColorSpace>& pCS); + RetainPtr<const CPDF_Stream> pShadingStream, + RetainPtr<CPDF_ColorSpace> pCS); ~CPDF_MeshStream(); bool Load(); + void SkipBits(uint32_t nbits); + void ByteAlign(); + bool IsEOF() const; bool CanReadFlag() const; bool CanReadCoords() const; bool CanReadColor() const; @@ -59,31 +63,30 @@ std::vector<CPDF_MeshVertex> ReadVertexRow(const CFX_Matrix& pObject2Bitmap, int count); - CFX_BitStream* BitStream() { return m_BitStream.get(); } uint32_t ComponentBits() const { return m_nComponentBits; } uint32_t Components() const { return m_nComponents; } private: - static const uint32_t kMaxComponents = 8; + static constexpr uint32_t kMaxComponents = 8; const ShadingType m_type; const std::vector<std::unique_ptr<CPDF_Function>>& m_funcs; RetainPtr<const CPDF_Stream> const m_pShadingStream; RetainPtr<CPDF_ColorSpace> const m_pCS; - uint32_t m_nCoordBits; - uint32_t m_nComponentBits; - uint32_t m_nFlagBits; - uint32_t m_nComponents; - uint32_t m_CoordMax; - uint32_t m_ComponentMax; - float m_xmin; - float m_xmax; - float m_ymin; - float m_ymax; + uint32_t m_nCoordBits = 0; + uint32_t m_nComponentBits = 0; + uint32_t m_nFlagBits = 0; + uint32_t m_nComponents = 0; + uint32_t m_CoordMax = 0; + uint32_t m_ComponentMax = 0; + float m_xmin = 0.0f; + float m_xmax = 0.0f; + float m_ymin = 0.0f; + float m_ymax = 0.0f; RetainPtr<CPDF_StreamAcc> m_pStream; std::unique_ptr<CFX_BitStream> m_BitStream; - float m_ColorMin[kMaxComponents]; - float m_ColorMax[kMaxComponents]; + float m_ColorMin[kMaxComponents] = {}; + float m_ColorMax[kMaxComponents] = {}; }; #endif // CORE_FPDFAPI_PAGE_CPDF_MESHSTREAM_H_
diff --git a/core/fpdfapi/page/cpdf_occontext.cpp b/core/fpdfapi/page/cpdf_occontext.cpp index 96f8a88..7d2b35f 100644 --- a/core/fpdfapi/page/cpdf_occontext.cpp +++ b/core/fpdfapi/page/cpdf_occontext.cpp
@@ -1,4 +1,4 @@ -// Copyright 2016 PDFium Authors. All rights reserved. +// Copyright 2016 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -10,31 +10,21 @@ #include "core/fpdfapi/parser/cpdf_array.h" #include "core/fpdfapi/parser/cpdf_dictionary.h" #include "core/fpdfapi/parser/cpdf_document.h" +#include "third_party/base/check.h" namespace { -int32_t FindGroup(const CPDF_Array* pArray, const CPDF_Dictionary* pGroupDict) { - if (!pArray || !pGroupDict) - return -1; - - for (size_t i = 0; i < pArray->size(); i++) { - if (pArray->GetDictAt(i) == pGroupDict) - return i; - } - return -1; -} - bool HasIntent(const CPDF_Dictionary* pDict, ByteStringView csElement, ByteStringView csDef) { - const CPDF_Object* pIntent = pDict->GetDirectObjectFor("Intent"); + RetainPtr<const CPDF_Object> pIntent = pDict->GetDirectObjectFor("Intent"); if (!pIntent) return csElement == csDef; ByteString bsIntent; if (const CPDF_Array* pArray = pIntent->AsArray()) { for (size_t i = 0; i < pArray->size(); i++) { - bsIntent = pArray->GetStringAt(i); + bsIntent = pArray->GetByteStringAt(i); if (bsIntent == "All" || bsIntent == csElement) return true; } @@ -44,28 +34,30 @@ return bsIntent == "All" || bsIntent == csElement; } -CPDF_Dictionary* GetConfig(CPDF_Document* pDoc, - const CPDF_Dictionary* pOCGDict) { - ASSERT(pOCGDict); - CPDF_Dictionary* pOCProperties = pDoc->GetRoot()->GetDictFor("OCProperties"); +RetainPtr<const CPDF_Dictionary> GetConfig(CPDF_Document* pDoc, + const CPDF_Dictionary* pOCGDict) { + DCHECK(pOCGDict); + RetainPtr<const CPDF_Dictionary> pOCProperties = + pDoc->GetRoot()->GetDictFor("OCProperties"); if (!pOCProperties) return nullptr; - CPDF_Array* pOCGs = pOCProperties->GetArrayFor("OCGs"); + RetainPtr<const CPDF_Array> pOCGs = pOCProperties->GetArrayFor("OCGs"); if (!pOCGs) return nullptr; - if (FindGroup(pOCGs, pOCGDict) < 0) + if (!pOCGs->Contains(pOCGDict)) return nullptr; - CPDF_Dictionary* pConfig = pOCProperties->GetDictFor("D"); - CPDF_Array* pConfigs = pOCProperties->GetArrayFor("Configs"); - if (!pConfigs) + RetainPtr<const CPDF_Dictionary> pConfig = pOCProperties->GetDictFor("D"); + RetainPtr<const CPDF_Array> pConfigArray = + pOCProperties->GetArrayFor("Configs"); + if (!pConfigArray) return pConfig; - for (size_t i = 0; i < pConfigs->size(); i++) { - CPDF_Dictionary* pFind = pConfigs->GetDictAt(i); - if (pFind && HasIntent(pFind, "View", "")) + for (size_t i = 0; i < pConfigArray->size(); i++) { + RetainPtr<const CPDF_Dictionary> pFind = pConfigArray->GetDictAt(i); + if (pFind && HasIntent(pFind.Get(), "View", "")) return pFind; } return pConfig; @@ -74,13 +66,13 @@ ByteString GetUsageTypeString(CPDF_OCContext::UsageType eType) { ByteString csState; switch (eType) { - case CPDF_OCContext::Design: + case CPDF_OCContext::kDesign: csState = "Design"; break; - case CPDF_OCContext::Print: + case CPDF_OCContext::kPrint: csState = "Print"; break; - case CPDF_OCContext::Export: + case CPDF_OCContext::kExport: csState = "Export"; break; default: @@ -94,54 +86,52 @@ CPDF_OCContext::CPDF_OCContext(CPDF_Document* pDoc, UsageType eUsageType) : m_pDocument(pDoc), m_eUsageType(eUsageType) { - ASSERT(pDoc); + DCHECK(pDoc); } -CPDF_OCContext::~CPDF_OCContext() {} +CPDF_OCContext::~CPDF_OCContext() = default; bool CPDF_OCContext::LoadOCGStateFromConfig( const ByteString& csConfig, const CPDF_Dictionary* pOCGDict) const { - CPDF_Dictionary* pConfig = GetConfig(m_pDocument.Get(), pOCGDict); + RetainPtr<const CPDF_Dictionary> pConfig = GetConfig(m_pDocument, pOCGDict); if (!pConfig) return true; - bool bState = pConfig->GetStringFor("BaseState", "ON") != "OFF"; - CPDF_Array* pArray = pConfig->GetArrayFor("ON"); - if (pArray) { - if (FindGroup(pArray, pOCGDict) >= 0) - bState = true; - } + bool bState = pConfig->GetByteStringFor("BaseState", "ON") != "OFF"; + RetainPtr<const CPDF_Array> pArray = pConfig->GetArrayFor("ON"); + if (pArray && pArray->Contains(pOCGDict)) + bState = true; + pArray = pConfig->GetArrayFor("OFF"); - if (pArray) { - if (FindGroup(pArray, pOCGDict) >= 0) - bState = false; - } + if (pArray && pArray->Contains(pOCGDict)) + bState = false; + pArray = pConfig->GetArrayFor("AS"); if (!pArray) return bState; ByteString csFind = csConfig + "State"; for (size_t i = 0; i < pArray->size(); i++) { - CPDF_Dictionary* pUsage = pArray->GetDictAt(i); + RetainPtr<const CPDF_Dictionary> pUsage = pArray->GetDictAt(i); if (!pUsage) continue; - if (pUsage->GetStringFor("Event", "View") != csConfig) + if (pUsage->GetByteStringFor("Event", "View") != csConfig) continue; - CPDF_Array* pOCGs = pUsage->GetArrayFor("OCGs"); + RetainPtr<const CPDF_Array> pOCGs = pUsage->GetArrayFor("OCGs"); if (!pOCGs) continue; - if (FindGroup(pOCGs, pOCGDict) < 0) + if (!pOCGs->Contains(pOCGDict)) continue; - CPDF_Dictionary* pState = pUsage->GetDictFor(csConfig); + RetainPtr<const CPDF_Dictionary> pState = pUsage->GetDictFor(csConfig); if (!pState) continue; - bState = pState->GetStringFor(csFind) != "OFF"; + bState = pState->GetByteStringFor(csFind) != "OFF"; } return bState; } @@ -151,18 +141,18 @@ return true; ByteString csState = GetUsageTypeString(m_eUsageType); - const CPDF_Dictionary* pUsage = pOCGDict->GetDictFor("Usage"); + RetainPtr<const CPDF_Dictionary> pUsage = pOCGDict->GetDictFor("Usage"); if (pUsage) { - const CPDF_Dictionary* pState = pUsage->GetDictFor(csState); + RetainPtr<const CPDF_Dictionary> pState = pUsage->GetDictFor(csState); if (pState) { ByteString csFind = csState + "State"; if (pState->KeyExist(csFind)) - return pState->GetStringFor(csFind) != "OFF"; + return pState->GetByteStringFor(csFind) != "OFF"; } if (csState != "View") { pState = pUsage->GetDictFor("View"); if (pState && pState->KeyExist("ViewState")) - return pState->GetStringFor("ViewState") != "OFF"; + return pState->GetByteStringFor("ViewState") != "OFF"; } } return LoadOCGStateFromConfig(csState, pOCGDict); @@ -177,16 +167,17 @@ return it->second; bool bState = LoadOCGState(pOCGDict); - m_OGCStateCache[pOCGDict] = bState; + m_OGCStateCache[pdfium::WrapRetain(pOCGDict)] = bState; return bState; } -bool CPDF_OCContext::CheckObjectVisible(const CPDF_PageObject* pObj) const { - for (size_t i = 0; i < pObj->m_ContentMarks.CountItems(); ++i) { - const CPDF_ContentMarkItem* item = pObj->m_ContentMarks.GetItem(i); +bool CPDF_OCContext::CheckPageObjectVisible(const CPDF_PageObject* pObj) const { + const CPDF_ContentMarks* pMarks = pObj->GetContentMarks(); + for (size_t i = 0; i < pMarks->CountItems(); ++i) { + const CPDF_ContentMarkItem* item = pMarks->GetItem(i); if (item->GetName() == "OC" && item->GetParamType() == CPDF_ContentMarkItem::kPropertiesDict && - !CheckOCGVisible(item->GetParam())) { + !CheckOCGDictVisible(item->GetParam().Get())) { return false; } } @@ -197,9 +188,9 @@ if (nLevel > 32 || !pExpression) return false; - ByteString csOperator = pExpression->GetStringAt(0); + ByteString csOperator = pExpression->GetByteStringAt(0); if (csOperator == "Not") { - const CPDF_Object* pOCGObj = pExpression->GetDirectObjectAt(1); + RetainPtr<const CPDF_Object> pOCGObj = pExpression->GetDirectObjectAt(1); if (!pOCGObj) return false; if (const CPDF_Dictionary* pDict = pOCGObj->AsDictionary()) @@ -214,7 +205,7 @@ bool bValue = false; for (size_t i = 1; i < pExpression->size(); i++) { - const CPDF_Object* pOCGObj = pExpression->GetDirectObjectAt(1); + RetainPtr<const CPDF_Object> pOCGObj = pExpression->GetDirectObjectAt(i); if (!pOCGObj) continue; @@ -238,12 +229,13 @@ } bool CPDF_OCContext::LoadOCMDState(const CPDF_Dictionary* pOCMDDict) const { - const CPDF_Array* pVE = pOCMDDict->GetArrayFor("VE"); - if (pVE) - return GetOCGVE(pVE, 0); + RetainPtr<const CPDF_Array> pVE = pOCMDDict->GetArrayFor("VE"); + if (pVE) { + return GetOCGVE(pVE.Get(), 0); + } - ByteString csP = pOCMDDict->GetStringFor("P", "AnyOn"); - const CPDF_Object* pOCGObj = pOCMDDict->GetDirectObjectFor("OCGs"); + ByteString csP = pOCMDDict->GetByteStringFor("P", "AnyOn"); + RetainPtr<const CPDF_Object> pOCGObj = pOCMDDict->GetDirectObjectFor("OCGs"); if (!pOCGObj) return true; @@ -260,12 +252,12 @@ bool bValidEntrySeen = false; for (size_t i = 0; i < pArray->size(); i++) { bool bItem = true; - const CPDF_Dictionary* pItemDict = pArray->GetDictAt(i); + RetainPtr<const CPDF_Dictionary> pItemDict = pArray->GetDictAt(i); if (!pItemDict) continue; bValidEntrySeen = true; - bItem = GetOCGVisible(pItemDict); + bItem = GetOCGVisible(pItemDict.Get()); if ((csP == "AnyOn" && bItem) || (csP == "AnyOff" && !bItem)) return true; @@ -276,11 +268,12 @@ return !bValidEntrySeen || bState; } -bool CPDF_OCContext::CheckOCGVisible(const CPDF_Dictionary* pOCGDict) const { +bool CPDF_OCContext::CheckOCGDictVisible( + const CPDF_Dictionary* pOCGDict) const { if (!pOCGDict) return true; - ByteString csType = pOCGDict->GetStringFor("Type", "OCG"); + ByteString csType = pOCGDict->GetByteStringFor("Type", "OCG"); if (csType == "OCG") return GetOCGVisible(pOCGDict); return LoadOCMDState(pOCGDict);
diff --git a/core/fpdfapi/page/cpdf_occontext.h b/core/fpdfapi/page/cpdf_occontext.h index 0a68639..c0012d1 100644 --- a/core/fpdfapi/page/cpdf_occontext.h +++ b/core/fpdfapi/page/cpdf_occontext.h
@@ -1,4 +1,4 @@ -// Copyright 2016 PDFium Authors. All rights reserved. +// Copyright 2016 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -7,10 +7,12 @@ #ifndef CORE_FPDFAPI_PAGE_CPDF_OCCONTEXT_H_ #define CORE_FPDFAPI_PAGE_CPDF_OCCONTEXT_H_ +#include <functional> #include <map> -#include "core/fxcrt/fx_string.h" +#include "core/fxcrt/bytestring.h" #include "core/fxcrt/retain_ptr.h" +#include "core/fxcrt/unowned_ptr.h" class CPDF_Array; class CPDF_Dictionary; @@ -19,13 +21,12 @@ class CPDF_OCContext final : public Retainable { public: - enum UsageType { View = 0, Design, Print, Export }; + enum UsageType { kView = 0, kDesign, kPrint, kExport }; - template <typename T, typename... Args> - friend RetainPtr<T> pdfium::MakeRetain(Args&&... args); + CONSTRUCT_VIA_MAKE_RETAIN; - bool CheckOCGVisible(const CPDF_Dictionary* pOCGDict) const; - bool CheckObjectVisible(const CPDF_PageObject* pObj) const; + bool CheckOCGDictVisible(const CPDF_Dictionary* pOCGDict) const; + bool CheckPageObjectVisible(const CPDF_PageObject* pObj) const; private: CPDF_OCContext(CPDF_Document* pDoc, UsageType eUsageType); @@ -40,7 +41,8 @@ UnownedPtr<CPDF_Document> const m_pDocument; const UsageType m_eUsageType; - mutable std::map<const CPDF_Dictionary*, bool> m_OGCStateCache; + mutable std::map<RetainPtr<const CPDF_Dictionary>, bool, std::less<>> + m_OGCStateCache; }; #endif // CORE_FPDFAPI_PAGE_CPDF_OCCONTEXT_H_
diff --git a/core/fpdfapi/page/cpdf_page.cpp b/core/fpdfapi/page/cpdf_page.cpp index 210f266..d3493de 100644 --- a/core/fpdfapi/page/cpdf_page.cpp +++ b/core/fpdfapi/page/cpdf_page.cpp
@@ -1,4 +1,4 @@ -// Copyright 2016 PDFium Authors. All rights reserved. +// Copyright 2016 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -11,24 +11,26 @@ #include "constants/page_object.h" #include "core/fpdfapi/page/cpdf_contentparser.h" +#include "core/fpdfapi/page/cpdf_pageimagecache.h" #include "core/fpdfapi/page/cpdf_pageobject.h" #include "core/fpdfapi/parser/cpdf_array.h" #include "core/fpdfapi/parser/cpdf_dictionary.h" #include "core/fpdfapi/parser/cpdf_object.h" -#include "third_party/base/ptr_util.h" -#include "third_party/base/stl_util.h" +#include "third_party/base/check.h" +#include "third_party/base/check_op.h" +#include "third_party/base/containers/contains.h" -CPDF_Page::CPDF_Page(CPDF_Document* pDocument, CPDF_Dictionary* pPageDict) - : CPDF_PageObjectHolder(pDocument, pPageDict, nullptr, nullptr), +CPDF_Page::CPDF_Page(CPDF_Document* pDocument, + RetainPtr<CPDF_Dictionary> pPageDict) + : CPDF_PageObjectHolder(pDocument, std::move(pPageDict), nullptr, nullptr), m_PageSize(100, 100), m_pPDFDocument(pDocument) { - ASSERT(pPageDict); - // Cannot initialize |m_pResources| and |m_pPageResources| via the // CPDF_PageObjectHolder ctor because GetPageAttr() requires // CPDF_PageObjectHolder to finish initializing first. - CPDF_Object* pPageAttr = GetPageAttr(pdfium::page_object::kResources); - m_pResources.Reset(pPageAttr ? pPageAttr->GetDict() : nullptr); + RetainPtr<CPDF_Object> pPageAttr = + GetMutablePageAttr(pdfium::page_object::kResources); + m_pResources = pPageAttr ? pPageAttr->GetMutableDict() : nullptr; m_pPageResources = m_pResources; UpdateDimensions(); @@ -36,7 +38,7 @@ LoadTransparencyInfo(); } -CPDF_Page::~CPDF_Page() {} +CPDF_Page::~CPDF_Page() = default; CPDF_Page* CPDF_Page::AsPDFPage() { return this; @@ -47,7 +49,7 @@ } CPDF_Document* CPDF_Page::GetDocument() const { - return GetPDFDocument(); + return m_pPDFDocument; } float CPDF_Page::GetPageWidth() const { @@ -67,30 +69,34 @@ return; if (GetParseState() == ParseState::kNotParsed) - StartParse(pdfium::MakeUnique<CPDF_ContentParser>(this)); + StartParse(std::make_unique<CPDF_ContentParser>(this)); - ASSERT(GetParseState() == ParseState::kParsing); + DCHECK_EQ(GetParseState(), ParseState::kParsing); ContinueParse(nullptr); } -CPDF_Object* CPDF_Page::GetPageAttr(const ByteString& name) const { - CPDF_Dictionary* pPageDict = GetDict(); - std::set<CPDF_Dictionary*> visited; - while (1) { - visited.insert(pPageDict); - if (CPDF_Object* pObj = pPageDict->GetDirectObjectFor(name)) +RetainPtr<CPDF_Object> CPDF_Page::GetMutablePageAttr(const ByteString& name) { + return pdfium::WrapRetain(const_cast<CPDF_Object*>(GetPageAttr(name).Get())); +} + +RetainPtr<const CPDF_Object> CPDF_Page::GetPageAttr( + const ByteString& name) const { + std::set<RetainPtr<const CPDF_Dictionary>> visited; + RetainPtr<const CPDF_Dictionary> pPageDict = GetDict(); + while (pPageDict && !pdfium::Contains(visited, pPageDict)) { + RetainPtr<const CPDF_Object> pObj = pPageDict->GetDirectObjectFor(name); + if (pObj) return pObj; + visited.insert(pPageDict); pPageDict = pPageDict->GetDictFor(pdfium::page_object::kParent); - if (!pPageDict || pdfium::ContainsKey(visited, pPageDict)) - break; } return nullptr; } CFX_FloatRect CPDF_Page::GetBox(const ByteString& name) const { CFX_FloatRect box; - CPDF_Array* pBox = ToArray(GetPageAttr(name)); + RetainPtr<const CPDF_Array> pBox = ToArray(GetPageAttr(name)); if (pBox) { box = pBox->GetRect(); box.Normalize(); @@ -98,7 +104,7 @@ return box; } -Optional<CFX_PointF> CPDF_Page::DeviceToPage( +absl::optional<CFX_PointF> CPDF_Page::DeviceToPage( const FX_RECT& rect, int rotate, const CFX_PointF& device_point) const { @@ -106,7 +112,7 @@ return page2device.GetInverse().Transform(device_point); } -Optional<CFX_PointF> CPDF_Page::PageToDevice( +absl::optional<CFX_PointF> CPDF_Page::PageToDevice( const FX_RECT& rect, int rotate, const CFX_PointF& page_point) const { @@ -172,11 +178,43 @@ } int CPDF_Page::GetPageRotation() const { - CPDF_Object* pRotate = GetPageAttr(pdfium::page_object::kRotate); + RetainPtr<const CPDF_Object> pRotate = + GetPageAttr(pdfium::page_object::kRotate); int rotate = pRotate ? (pRotate->GetInteger() / 90) % 4 : 0; return (rotate < 0) ? (rotate + 4) : rotate; } +RetainPtr<CPDF_Array> CPDF_Page::GetOrCreateAnnotsArray() { + return GetMutableDict()->GetOrCreateArrayFor("Annots"); +} + +RetainPtr<CPDF_Array> CPDF_Page::GetMutableAnnotsArray() { + return GetMutableDict()->GetMutableArrayFor("Annots"); +} + +RetainPtr<const CPDF_Array> CPDF_Page::GetAnnotsArray() const { + return GetDict()->GetArrayFor("Annots"); +} + +void CPDF_Page::AddPageImageCache() { + m_pPageImageCache = std::make_unique<CPDF_PageImageCache>(this); +} + +void CPDF_Page::SetRenderContext(std::unique_ptr<RenderContextIface> pContext) { + DCHECK(!m_pRenderContext); + DCHECK(pContext); + m_pRenderContext = std::move(pContext); +} + +void CPDF_Page::ClearRenderContext() { + m_pRenderContext.reset(); +} + +void CPDF_Page::ClearView() { + if (m_pView) + m_pView->ClearPage(this); +} + void CPDF_Page::UpdateDimensions() { CFX_FloatRect mediabox = GetBox(pdfium::page_object::kMediaBox); if (mediabox.IsEmpty()) @@ -214,5 +252,6 @@ : m_pPage(pPage) {} CPDF_Page::RenderContextClearer::~RenderContextClearer() { - m_pPage->SetRenderContext(nullptr); + if (m_pPage) + m_pPage->ClearRenderContext(); }
diff --git a/core/fpdfapi/page/cpdf_page.h b/core/fpdfapi/page/cpdf_page.h index 9bdb75d..2b659e6 100644 --- a/core/fpdfapi/page/cpdf_page.h +++ b/core/fpdfapi/page/cpdf_page.h
@@ -1,4 +1,4 @@ -// Copyright 2016 PDFium Authors. All rights reserved. +// Copyright 2016 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -13,37 +13,35 @@ #include "core/fpdfapi/page/cpdf_pageobjectholder.h" #include "core/fpdfapi/page/ipdf_page.h" #include "core/fxcrt/fx_coordinates.h" -#include "core/fxcrt/fx_system.h" +#include "core/fxcrt/fx_memory.h" #include "core/fxcrt/observed_ptr.h" #include "core/fxcrt/retain_ptr.h" #include "core/fxcrt/unowned_ptr.h" -#include "third_party/base/optional.h" +#include "third_party/abseil-cpp/absl/types/optional.h" +class CPDF_Array; class CPDF_Dictionary; class CPDF_Document; -class CPDF_Image; class CPDF_Object; +class CPDF_PageImageCache; class CPDF_Page final : public IPDF_Page, public CPDF_PageObjectHolder { public: - // Caller implements as desired, empty here due to layering. - class View : public Observable {}; + // Caller implements as desired, exists here due to layering. + class View : public Observable { + public: + virtual void ClearPage(CPDF_Page* pPage) = 0; + }; // Data for the render layer to attach to this page. class RenderContextIface { public: - virtual ~RenderContextIface() {} - }; - - // Cache for the render layer to attach to this page. - class RenderCacheIface { - public: - virtual ~RenderCacheIface() {} - virtual void ResetBitmapForImage(const RetainPtr<CPDF_Image>& pImage) = 0; + virtual ~RenderContextIface() = default; }; class RenderContextClearer { public: + FX_STACK_ALLOCATED(); explicit RenderContextClearer(CPDF_Page* pPage); ~RenderContextClearer(); @@ -51,8 +49,7 @@ UnownedPtr<CPDF_Page> const m_pPage; }; - template <typename T, typename... Args> - friend RetainPtr<T> pdfium::MakeRetain(Args&&... args); + CONSTRUCT_VIA_MAKE_RETAIN; // IPDF_Page: CPDF_Page* AsPDFPage() override; @@ -61,11 +58,11 @@ float GetPageWidth() const override; float GetPageHeight() const override; CFX_Matrix GetDisplayMatrix(const FX_RECT& rect, int iRotate) const override; - Optional<CFX_PointF> DeviceToPage( + absl::optional<CFX_PointF> DeviceToPage( const FX_RECT& rect, int rotate, const CFX_PointF& device_point) const override; - Optional<CFX_PointF> PageToDevice( + absl::optional<CFX_PointF> PageToDevice( const FX_RECT& rect, int rotate, const CFX_PointF& page_point) const override; @@ -75,35 +72,39 @@ void ParseContent(); const CFX_SizeF& GetPageSize() const { return m_PageSize; } + const CFX_Matrix& GetPageMatrix() const { return m_PageMatrix; } int GetPageRotation() const; - RenderCacheIface* GetRenderCache() const { return m_pRenderCache.get(); } - void SetRenderCache(std::unique_ptr<RenderCacheIface> pCache) { - m_pRenderCache = std::move(pCache); - } - RenderContextIface* GetRenderContext() const { - return m_pRenderContext.get(); - } - void SetRenderContext(std::unique_ptr<RenderContextIface> pContext) { - m_pRenderContext = std::move(pContext); - } + RetainPtr<CPDF_Array> GetOrCreateAnnotsArray(); + RetainPtr<CPDF_Array> GetMutableAnnotsArray(); + RetainPtr<const CPDF_Array> GetAnnotsArray() const; - CPDF_Document* GetPDFDocument() const { return m_pPDFDocument.Get(); } - View* GetView() const { return m_pView.Get(); } + void AddPageImageCache(); + CPDF_PageImageCache* GetPageImageCache() { return m_pPageImageCache.get(); } + RenderContextIface* GetRenderContext() { return m_pRenderContext.get(); } + + // `pContext` cannot be null. `SetRenderContext()` cannot be called if the + // page already has a render context. Use `ClearRenderContext()` to reset the + // render context. + void SetRenderContext(std::unique_ptr<RenderContextIface> pContext); + void ClearRenderContext(); + void SetView(View* pView) { m_pView.Reset(pView); } + void ClearView(); void UpdateDimensions(); private: - CPDF_Page(CPDF_Document* pDocument, CPDF_Dictionary* pPageDict); + CPDF_Page(CPDF_Document* pDocument, RetainPtr<CPDF_Dictionary> pPageDict); ~CPDF_Page() override; - CPDF_Object* GetPageAttr(const ByteString& name) const; + RetainPtr<CPDF_Object> GetMutablePageAttr(const ByteString& name); + RetainPtr<const CPDF_Object> GetPageAttr(const ByteString& name) const; CFX_FloatRect GetBox(const ByteString& name) const; CFX_SizeF m_PageSize; CFX_Matrix m_PageMatrix; - UnownedPtr<CPDF_Document> m_pPDFDocument; - std::unique_ptr<RenderCacheIface> m_pRenderCache; + UnownedPtr<CPDF_Document> const m_pPDFDocument; + std::unique_ptr<CPDF_PageImageCache> m_pPageImageCache; std::unique_ptr<RenderContextIface> m_pRenderContext; ObservedPtr<View> m_pView; };
diff --git a/core/fpdfapi/page/cpdf_pageimagecache.cpp b/core/fpdfapi/page/cpdf_pageimagecache.cpp new file mode 100644 index 0000000..497cd8b --- /dev/null +++ b/core/fpdfapi/page/cpdf_pageimagecache.cpp
@@ -0,0 +1,262 @@ +// Copyright 2016 The PDFium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com + +#include "core/fpdfapi/page/cpdf_pageimagecache.h" + +#include <algorithm> +#include <utility> +#include <vector> + +#include "core/fpdfapi/page/cpdf_dib.h" +#include "core/fpdfapi/page/cpdf_image.h" +#include "core/fpdfapi/page/cpdf_page.h" +#include "core/fpdfapi/parser/cpdf_dictionary.h" +#include "core/fpdfapi/parser/cpdf_document.h" +#include "core/fpdfapi/parser/cpdf_stream.h" +#include "core/fxcrt/stl_util.h" +#include "core/fxge/dib/cfx_dibitmap.h" + +namespace { + +struct CacheInfo { + CacheInfo(uint32_t t, RetainPtr<const CPDF_Stream> stream) + : time(t), pStream(std::move(stream)) {} + + uint32_t time; + RetainPtr<const CPDF_Stream> pStream; + + bool operator<(const CacheInfo& other) const { return time < other.time; } +}; + +} // namespace + +CPDF_PageImageCache::CPDF_PageImageCache(CPDF_Page* pPage) : m_pPage(pPage) {} + +CPDF_PageImageCache::~CPDF_PageImageCache() = default; + +void CPDF_PageImageCache::CacheOptimization(int32_t dwLimitCacheSize) { + if (m_nCacheSize <= (uint32_t)dwLimitCacheSize) + return; + + uint32_t nCount = fxcrt::CollectionSize<uint32_t>(m_ImageCache); + std::vector<CacheInfo> cache_info; + cache_info.reserve(nCount); + for (const auto& it : m_ImageCache) { + cache_info.emplace_back(it.second->GetTimeCount(), + it.second->GetImage()->GetStream()); + } + std::sort(cache_info.begin(), cache_info.end()); + + // Check if time value is about to roll over and reset all entries. + // The comparison is legal because uint32_t is an unsigned type. + uint32_t nTimeCount = m_nTimeCount; + if (nTimeCount + 1 < nTimeCount) { + for (uint32_t i = 0; i < nCount; i++) + m_ImageCache[cache_info[i].pStream]->SetTimeCount(i); + m_nTimeCount = nCount; + } + + size_t i = 0; + while (i + 15 < nCount) + ClearImageCacheEntry(cache_info[i++].pStream); + + while (i < nCount && m_nCacheSize > (uint32_t)dwLimitCacheSize) + ClearImageCacheEntry(cache_info[i++].pStream); +} + +void CPDF_PageImageCache::ClearImageCacheEntry(const CPDF_Stream* pStream) { + auto it = m_ImageCache.find(pStream); + if (it == m_ImageCache.end()) + return; + + m_nCacheSize -= it->second->EstimateSize(); + + // Avoid leaving `m_pCurImageCacheEntry` as a dangling pointer when `it` is + // about to be deleted. + if (m_pCurImageCacheEntry.Get() == it->second.get()) { + DCHECK(!m_pCurImageCacheEntry.IsOwned()); + m_pCurImageCacheEntry.Reset(); + } + m_ImageCache.erase(it); +} + +bool CPDF_PageImageCache::StartGetCachedBitmap( + RetainPtr<CPDF_Image> pImage, + const CPDF_Dictionary* pFormResources, + const CPDF_Dictionary* pPageResources, + bool bStdCS, + CPDF_ColorSpace::Family eFamily, + bool bLoadMask, + const CFX_Size& max_size_required) { + // A cross-document image may have come from the embedder. + if (m_pPage->GetDocument() != pImage->GetDocument()) + return false; + + RetainPtr<const CPDF_Stream> pStream = pImage->GetStream(); + const auto it = m_ImageCache.find(pStream); + m_bCurFindCache = it != m_ImageCache.end(); + if (m_bCurFindCache) { + m_pCurImageCacheEntry = it->second.get(); + } else { + m_pCurImageCacheEntry = std::make_unique<Entry>(std::move(pImage)); + } + CPDF_DIB::LoadState ret = m_pCurImageCacheEntry->StartGetCachedBitmap( + this, pFormResources, pPageResources, bStdCS, eFamily, bLoadMask, + max_size_required); + if (ret == CPDF_DIB::LoadState::kContinue) + return true; + + m_nTimeCount++; + if (!m_bCurFindCache) + m_ImageCache[pStream] = m_pCurImageCacheEntry.Release(); + + if (ret == CPDF_DIB::LoadState::kFail) + m_nCacheSize += m_pCurImageCacheEntry->EstimateSize(); + + return false; +} + +bool CPDF_PageImageCache::Continue(PauseIndicatorIface* pPause) { + bool ret = m_pCurImageCacheEntry->Continue(pPause, this); + if (ret) + return true; + + m_nTimeCount++; + if (!m_bCurFindCache) { + m_ImageCache[m_pCurImageCacheEntry->GetImage()->GetStream()] = + m_pCurImageCacheEntry.Release(); + } + m_nCacheSize += m_pCurImageCacheEntry->EstimateSize(); + return false; +} + +void CPDF_PageImageCache::ResetBitmapForImage(RetainPtr<CPDF_Image> pImage) { + RetainPtr<const CPDF_Stream> pStream = pImage->GetStream(); + const auto it = m_ImageCache.find(pStream); + if (it == m_ImageCache.end()) + return; + + Entry* pEntry = it->second.get(); + m_nCacheSize -= pEntry->EstimateSize(); + pEntry->Reset(); + m_nCacheSize += pEntry->EstimateSize(); +} + +uint32_t CPDF_PageImageCache::GetCurMatteColor() const { + return m_pCurImageCacheEntry->GetMatteColor(); +} + +RetainPtr<CFX_DIBBase> CPDF_PageImageCache::DetachCurBitmap() { + return m_pCurImageCacheEntry->DetachBitmap(); +} + +RetainPtr<CFX_DIBBase> CPDF_PageImageCache::DetachCurMask() { + return m_pCurImageCacheEntry->DetachMask(); +} + +CPDF_PageImageCache::Entry::Entry(RetainPtr<CPDF_Image> pImage) + : m_pImage(std::move(pImage)) {} + +CPDF_PageImageCache::Entry::~Entry() = default; + +void CPDF_PageImageCache::Entry::Reset() { + m_pCachedBitmap.Reset(); + CalcSize(); +} + +RetainPtr<CFX_DIBBase> CPDF_PageImageCache::Entry::DetachBitmap() { + return std::move(m_pCurBitmap); +} + +RetainPtr<CFX_DIBBase> CPDF_PageImageCache::Entry::DetachMask() { + return std::move(m_pCurMask); +} + +CPDF_DIB::LoadState CPDF_PageImageCache::Entry::StartGetCachedBitmap( + CPDF_PageImageCache* pPageImageCache, + const CPDF_Dictionary* pFormResources, + const CPDF_Dictionary* pPageResources, + bool bStdCS, + CPDF_ColorSpace::Family eFamily, + bool bLoadMask, + const CFX_Size& max_size_required) { + if (m_pCachedBitmap && IsCacheValid(max_size_required)) { + m_pCurBitmap = m_pCachedBitmap; + m_pCurMask = m_pCachedMask; + return CPDF_DIB::LoadState::kSuccess; + } + + m_pCurBitmap = m_pImage->CreateNewDIB(); + CPDF_DIB::LoadState ret = m_pCurBitmap.AsRaw<CPDF_DIB>()->StartLoadDIBBase( + true, pFormResources, pPageResources, bStdCS, eFamily, bLoadMask, + max_size_required); + m_bCachedSetMaxSizeRequired = + (max_size_required.width != 0 && max_size_required.height != 0); + if (ret == CPDF_DIB::LoadState::kContinue) + return CPDF_DIB::LoadState::kContinue; + + if (ret == CPDF_DIB::LoadState::kSuccess) + ContinueGetCachedBitmap(pPageImageCache); + else + m_pCurBitmap.Reset(); + return CPDF_DIB::LoadState::kFail; +} + +bool CPDF_PageImageCache::Entry::Continue( + PauseIndicatorIface* pPause, + CPDF_PageImageCache* pPageImageCache) { + CPDF_DIB::LoadState ret = + m_pCurBitmap.AsRaw<CPDF_DIB>()->ContinueLoadDIBBase(pPause); + if (ret == CPDF_DIB::LoadState::kContinue) + return true; + + if (ret == CPDF_DIB::LoadState::kSuccess) + ContinueGetCachedBitmap(pPageImageCache); + else + m_pCurBitmap.Reset(); + return false; +} + +void CPDF_PageImageCache::Entry::ContinueGetCachedBitmap( + CPDF_PageImageCache* pPageImageCache) { + m_MatteColor = m_pCurBitmap.AsRaw<CPDF_DIB>()->GetMatteColor(); + m_pCurMask = m_pCurBitmap.AsRaw<CPDF_DIB>()->DetachMask(); + m_dwTimeCount = pPageImageCache->GetTimeCount(); + if (m_pCurBitmap->GetPitch() * m_pCurBitmap->GetHeight() < kHugeImageSize) { + m_pCachedBitmap = m_pCurBitmap->Realize(); + m_pCurBitmap.Reset(); + } else { + m_pCachedBitmap = m_pCurBitmap; + } + if (m_pCurMask) { + m_pCachedMask = m_pCurMask->Realize(); + m_pCurMask.Reset(); + } + m_pCurBitmap = m_pCachedBitmap; + m_pCurMask = m_pCachedMask; + CalcSize(); +} + +void CPDF_PageImageCache::Entry::CalcSize() { + m_dwCacheSize = 0; + if (m_pCachedBitmap) + m_dwCacheSize += m_pCachedBitmap->GetEstimatedImageMemoryBurden(); + if (m_pCachedMask) + m_dwCacheSize += m_pCachedMask->GetEstimatedImageMemoryBurden(); +} + +bool CPDF_PageImageCache::Entry::IsCacheValid( + const CFX_Size& max_size_required) const { + if (!m_bCachedSetMaxSizeRequired) { + return true; + } + if (max_size_required.width == 0 && max_size_required.height == 0) { + return false; + } + + return (m_pCachedBitmap->GetWidth() >= max_size_required.width) && + (m_pCachedBitmap->GetHeight() >= max_size_required.height); +}
diff --git a/core/fpdfapi/page/cpdf_pageimagecache.h b/core/fpdfapi/page/cpdf_pageimagecache.h new file mode 100644 index 0000000..5184ff6 --- /dev/null +++ b/core/fpdfapi/page/cpdf_pageimagecache.h
@@ -0,0 +1,107 @@ +// Copyright 2016 The PDFium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com + +#ifndef CORE_FPDFAPI_PAGE_CPDF_PAGEIMAGECACHE_H_ +#define CORE_FPDFAPI_PAGE_CPDF_PAGEIMAGECACHE_H_ + +#include <stdint.h> + +#include <functional> +#include <map> +#include <memory> + +#include "core/fpdfapi/page/cpdf_dib.h" +#include "core/fxcrt/maybe_owned.h" +#include "core/fxcrt/retain_ptr.h" +#include "core/fxcrt/unowned_ptr.h" + +class CPDF_Dictionary; +class CPDF_Image; +class CPDF_Page; +class CPDF_Stream; +class PauseIndicatorIface; + +class CPDF_PageImageCache { + public: + explicit CPDF_PageImageCache(CPDF_Page* pPage); + ~CPDF_PageImageCache(); + + void ResetBitmapForImage(RetainPtr<CPDF_Image> pImage); + void CacheOptimization(int32_t dwLimitCacheSize); + uint32_t GetTimeCount() const { return m_nTimeCount; } + CPDF_Page* GetPage() const { return m_pPage; } + + bool StartGetCachedBitmap(RetainPtr<CPDF_Image> pImage, + const CPDF_Dictionary* pFormResources, + const CPDF_Dictionary* pPageResources, + bool bStdCS, + CPDF_ColorSpace::Family eFamily, + bool bLoadMask, + const CFX_Size& max_size_required); + + bool Continue(PauseIndicatorIface* pPause); + + uint32_t GetCurMatteColor() const; + RetainPtr<CFX_DIBBase> DetachCurBitmap(); + RetainPtr<CFX_DIBBase> DetachCurMask(); + + private: + class Entry { + public: + explicit Entry(RetainPtr<CPDF_Image> pImage); + ~Entry(); + + void Reset(); + uint32_t EstimateSize() const { return m_dwCacheSize; } + uint32_t GetMatteColor() const { return m_MatteColor; } + uint32_t GetTimeCount() const { return m_dwTimeCount; } + void SetTimeCount(uint32_t count) { m_dwTimeCount = count; } + CPDF_Image* GetImage() const { return m_pImage.Get(); } + + CPDF_DIB::LoadState StartGetCachedBitmap( + CPDF_PageImageCache* pPageImageCache, + const CPDF_Dictionary* pFormResources, + const CPDF_Dictionary* pPageResources, + bool bStdCS, + CPDF_ColorSpace::Family eFamily, + bool bLoadMask, + const CFX_Size& max_size_required); + + // Returns whether to Continue() or not. + bool Continue(PauseIndicatorIface* pPause, + CPDF_PageImageCache* pPageImageCache); + + RetainPtr<CFX_DIBBase> DetachBitmap(); + RetainPtr<CFX_DIBBase> DetachMask(); + + private: + void ContinueGetCachedBitmap(CPDF_PageImageCache* pPageImageCache); + void CalcSize(); + bool IsCacheValid(const CFX_Size& max_size_required) const; + + uint32_t m_dwTimeCount = 0; + uint32_t m_MatteColor = 0; + uint32_t m_dwCacheSize = 0; + RetainPtr<CPDF_Image> const m_pImage; + RetainPtr<CFX_DIBBase> m_pCurBitmap; + RetainPtr<CFX_DIBBase> m_pCurMask; + RetainPtr<CFX_DIBBase> m_pCachedBitmap; + RetainPtr<CFX_DIBBase> m_pCachedMask; + bool m_bCachedSetMaxSizeRequired = false; + }; + + void ClearImageCacheEntry(const CPDF_Stream* pStream); + + UnownedPtr<CPDF_Page> const m_pPage; + std::map<RetainPtr<const CPDF_Stream>, std::unique_ptr<Entry>, std::less<>> + m_ImageCache; + MaybeOwned<Entry> m_pCurImageCacheEntry; + uint32_t m_nTimeCount = 0; + uint32_t m_nCacheSize = 0; + bool m_bCurFindCache = false; +}; + +#endif // CORE_FPDFAPI_PAGE_CPDF_PAGEIMAGECACHE_H_
diff --git a/core/fpdfapi/page/cpdf_pageimagecache_unittest.cpp b/core/fpdfapi/page/cpdf_pageimagecache_unittest.cpp new file mode 100644 index 0000000..34e436f --- /dev/null +++ b/core/fpdfapi/page/cpdf_pageimagecache_unittest.cpp
@@ -0,0 +1,81 @@ +// Copyright 2023 The PDFium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "core/fpdfapi/page/cpdf_pageimagecache.h" + +#include <memory> +#include <string> +#include <utility> + +#include "core/fpdfapi/page/cpdf_docpagedata.h" +#include "core/fpdfapi/page/cpdf_image.h" +#include "core/fpdfapi/page/cpdf_imageobject.h" +#include "core/fpdfapi/page/cpdf_page.h" +#include "core/fpdfapi/page/cpdf_pagemodule.h" +#include "core/fpdfapi/parser/cpdf_parser.h" +#include "core/fpdfapi/render/cpdf_docrenderdata.h" +#include "core/fxcrt/fx_stream.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "testing/utils/path_service.h" + +TEST(CPDFPageImageCache, RenderBug1924) { + // If you render a page with a JPEG2000 image as a thumbnail (small picture) + // first, the image that gets cached has a low resolution. If you afterwards + // render it full-size, you should get a larger image - the image cache will + // be regenerate. + + CPDF_PageModule::Create(); + { + std::string file_path; + ASSERT_TRUE(PathService::GetTestFilePath("jpx_lzw.pdf", &file_path)); + auto document = + std::make_unique<CPDF_Document>(std::make_unique<CPDF_DocRenderData>(), + std::make_unique<CPDF_DocPageData>()); + ASSERT_EQ(document->LoadDoc( + IFX_SeekableReadStream::CreateFromFilename(file_path.c_str()), + nullptr), + CPDF_Parser::SUCCESS); + + RetainPtr<CPDF_Dictionary> page_dict = + document->GetMutablePageDictionary(0); + ASSERT_TRUE(page_dict); + auto page = + pdfium::MakeRetain<CPDF_Page>(document.get(), std::move(page_dict)); + page->AddPageImageCache(); + page->ParseContent(); + + CPDF_PageImageCache* page_image_cache = page->GetPageImageCache(); + ASSERT_TRUE(page_image_cache); + + CPDF_PageObject* page_obj = page->GetPageObjectByIndex(0); + ASSERT_TRUE(page_obj); + CPDF_ImageObject* image = page_obj->AsImage(); + ASSERT_TRUE(image); + + // Render with small scale. + bool should_continue = page_image_cache->StartGetCachedBitmap( + image->GetImage(), nullptr, page->GetMutablePageResources(), true, + CPDF_ColorSpace::Family::kICCBased, false, {50, 50}); + while (should_continue) + should_continue = page_image_cache->Continue(nullptr); + + RetainPtr<CFX_DIBBase> bitmap_small = page_image_cache->DetachCurBitmap(); + + // And render with large scale. + should_continue = page_image_cache->StartGetCachedBitmap( + image->GetImage(), nullptr, page->GetMutablePageResources(), true, + CPDF_ColorSpace::Family::kICCBased, false, {100, 100}); + while (should_continue) + should_continue = page_image_cache->Continue(nullptr); + + RetainPtr<CFX_DIBBase> bitmap_large = page_image_cache->DetachCurBitmap(); + + ASSERT_GT(bitmap_large->GetWidth(), bitmap_small->GetWidth()); + ASSERT_GT(bitmap_large->GetHeight(), bitmap_small->GetHeight()); + + ASSERT_TRUE(page->AsPDFPage()); + page->AsPDFPage()->ClearView(); + } + CPDF_PageModule::Destroy(); +}
diff --git a/core/fpdfapi/page/cpdf_pagemodule.cpp b/core/fpdfapi/page/cpdf_pagemodule.cpp index 705d313..6cda676 100644 --- a/core/fpdfapi/page/cpdf_pagemodule.cpp +++ b/core/fpdfapi/page/cpdf_pagemodule.cpp
@@ -1,4 +1,4 @@ -// Copyright 2016 PDFium Authors. All rights reserved. +// Copyright 2016 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -10,7 +10,7 @@ #include "core/fpdfapi/page/cpdf_colorspace.h" #include "core/fpdfapi/page/cpdf_devicecs.h" #include "core/fpdfapi/page/cpdf_patterncs.h" -#include "core/fxcodec/fx_codec.h" +#include "third_party/base/check.h" namespace { @@ -20,30 +20,31 @@ // static void CPDF_PageModule::Create() { - ASSERT(!g_PageModule); - fxcodec::ModuleMgr::Create(); + DCHECK(!g_PageModule); g_PageModule = new CPDF_PageModule(); } // static void CPDF_PageModule::Destroy() { - ASSERT(g_PageModule); + DCHECK(g_PageModule); delete g_PageModule; g_PageModule = nullptr; - fxcodec::ModuleMgr::Destroy(); } // static CPDF_PageModule* CPDF_PageModule::GetInstance() { - ASSERT(g_PageModule); + DCHECK(g_PageModule); return g_PageModule; } CPDF_PageModule::CPDF_PageModule() - : m_StockGrayCS(pdfium::MakeRetain<CPDF_DeviceCS>(PDFCS_DEVICEGRAY)), - m_StockRGBCS(pdfium::MakeRetain<CPDF_DeviceCS>(PDFCS_DEVICERGB)), - m_StockCMYKCS(pdfium::MakeRetain<CPDF_DeviceCS>(PDFCS_DEVICECMYK)), - m_StockPatternCS(pdfium::MakeRetain<CPDF_PatternCS>(nullptr)) { + : m_StockGrayCS(pdfium::MakeRetain<CPDF_DeviceCS>( + CPDF_ColorSpace::Family::kDeviceGray)), + m_StockRGBCS(pdfium::MakeRetain<CPDF_DeviceCS>( + CPDF_ColorSpace::Family::kDeviceRGB)), + m_StockCMYKCS(pdfium::MakeRetain<CPDF_DeviceCS>( + CPDF_ColorSpace::Family::kDeviceCMYK)), + m_StockPatternCS(pdfium::MakeRetain<CPDF_PatternCS>()) { m_StockPatternCS->InitializeStockPattern(); CPDF_FontGlobals::Create(); CPDF_FontGlobals::GetInstance()->LoadEmbeddedMaps(); @@ -53,14 +54,15 @@ CPDF_FontGlobals::Destroy(); } -RetainPtr<CPDF_ColorSpace> CPDF_PageModule::GetStockCS(int family) { - if (family == PDFCS_DEVICEGRAY) +RetainPtr<CPDF_ColorSpace> CPDF_PageModule::GetStockCS( + CPDF_ColorSpace::Family family) { + if (family == CPDF_ColorSpace::Family::kDeviceGray) return m_StockGrayCS; - if (family == PDFCS_DEVICERGB) + if (family == CPDF_ColorSpace::Family::kDeviceRGB) return m_StockRGBCS; - if (family == PDFCS_DEVICECMYK) + if (family == CPDF_ColorSpace::Family::kDeviceCMYK) return m_StockCMYKCS; - if (family == PDFCS_PATTERN) + if (family == CPDF_ColorSpace::Family::kPattern) return m_StockPatternCS; return nullptr; }
diff --git a/core/fpdfapi/page/cpdf_pagemodule.h b/core/fpdfapi/page/cpdf_pagemodule.h index e7234b9..dfd1308 100644 --- a/core/fpdfapi/page/cpdf_pagemodule.h +++ b/core/fpdfapi/page/cpdf_pagemodule.h
@@ -1,4 +1,4 @@ -// Copyright 2016 PDFium Authors. All rights reserved. +// Copyright 2016 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -7,10 +7,10 @@ #ifndef CORE_FPDFAPI_PAGE_CPDF_PAGEMODULE_H_ #define CORE_FPDFAPI_PAGE_CPDF_PAGEMODULE_H_ +#include "core/fpdfapi/page/cpdf_colorspace.h" #include "core/fxcrt/retain_ptr.h" class CPDF_Document; -class CPDF_ColorSpace; class CPDF_DeviceCS; class CPDF_PatternCS; @@ -21,7 +21,7 @@ static void Destroy(); static CPDF_PageModule* GetInstance(); - RetainPtr<CPDF_ColorSpace> GetStockCS(int family); + RetainPtr<CPDF_ColorSpace> GetStockCS(CPDF_ColorSpace::Family family); void ClearStockFont(CPDF_Document* pDoc); private:
diff --git a/core/fpdfapi/page/cpdf_pageobject.cpp b/core/fpdfapi/page/cpdf_pageobject.cpp index bde1704..8636af6 100644 --- a/core/fpdfapi/page/cpdf_pageobject.cpp +++ b/core/fpdfapi/page/cpdf_pageobject.cpp
@@ -1,4 +1,4 @@ -// Copyright 2016 PDFium Authors. All rights reserved. +// Copyright 2016 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -6,6 +6,8 @@ #include "core/fpdfapi/page/cpdf_pageobject.h" +#include "core/fxcrt/fx_coordinates.h" + CPDF_PageObject::CPDF_PageObject(int32_t content_stream) : m_ContentStream(content_stream) {}
diff --git a/core/fpdfapi/page/cpdf_pageobject.h b/core/fpdfapi/page/cpdf_pageobject.h index f840214..7d9d015 100644 --- a/core/fpdfapi/page/cpdf_pageobject.h +++ b/core/fpdfapi/page/cpdf_pageobject.h
@@ -1,4 +1,4 @@ -// Copyright 2016 PDFium Authors. All rights reserved. +// Copyright 2016 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -7,10 +7,12 @@ #ifndef CORE_FPDFAPI_PAGE_CPDF_PAGEOBJECT_H_ #define CORE_FPDFAPI_PAGE_CPDF_PAGEOBJECT_H_ +#include <stdint.h> + #include "core/fpdfapi/page/cpdf_contentmarks.h" #include "core/fpdfapi/page/cpdf_graphicstates.h" +#include "core/fxcrt/bytestring.h" #include "core/fxcrt/fx_coordinates.h" -#include "core/fxcrt/fx_system.h" class CPDF_FormObject; class CPDF_ImageObject; @@ -18,14 +20,18 @@ class CPDF_ShadingObject; class CPDF_TextObject; +// Represents an object within the page, like a form or image. Not to be +// confused with the PDF spec's page object that lives in a page tree, which is +// represented by CPDF_Page. class CPDF_PageObject : public CPDF_GraphicStates { public: - enum Type { - TEXT = 1, - PATH, - IMAGE, - SHADING, - FORM, + // Values must match corresponding values in //public. + enum class Type { + kText = 1, + kPath, + kImage, + kShading, + kForm, }; static constexpr int32_t kNoContentStream = -1; @@ -58,11 +64,19 @@ void TransformClipPath(const CFX_Matrix& matrix); void TransformGeneralState(const CFX_Matrix& matrix); + void SetOriginalRect(const CFX_FloatRect& rect) { m_OriginalRect = rect; } + const CFX_FloatRect& GetOriginalRect() const { return m_OriginalRect; } void SetRect(const CFX_FloatRect& rect) { m_Rect = rect; } const CFX_FloatRect& GetRect() const { return m_Rect; } FX_RECT GetBBox() const; FX_RECT GetTransformedBBox(const CFX_Matrix& matrix) const; + CPDF_ContentMarks* GetContentMarks() { return &m_ContentMarks; } + const CPDF_ContentMarks* GetContentMarks() const { return &m_ContentMarks; } + void SetContentMarks(const CPDF_ContentMarks& marks) { + m_ContentMarks = marks; + } + // Get what content stream the object was parsed from in its page. This number // is the index of the content stream in the "Contents" array, or 0 if there // is a single content stream. If the object is newly created, @@ -75,16 +89,29 @@ m_ContentStream = new_content_stream; } - CPDF_ContentMarks m_ContentMarks; + const ByteString& GetResourceName() const { return m_ResourceName; } + void SetResourceName(const ByteString& resource_name) { + m_ResourceName = resource_name; + } + + const ByteString& GetGraphicsResourceName() const { + return m_GraphicsResourceName; + } + void SetGraphicsResourceName(const ByteString& resource_name) { + m_GraphicsResourceName = resource_name; + } protected: void CopyData(const CPDF_PageObject* pSrcObject); - CFX_FloatRect m_Rect; - private: + CFX_FloatRect m_Rect; + CFX_FloatRect m_OriginalRect; + CPDF_ContentMarks m_ContentMarks; bool m_bDirty = false; int32_t m_ContentStream; + ByteString m_ResourceName; // The resource name for this object. + ByteString m_GraphicsResourceName; // Like `m_ResourceName` but for graphics. }; #endif // CORE_FPDFAPI_PAGE_CPDF_PAGEOBJECT_H_
diff --git a/core/fpdfapi/page/cpdf_pageobjectholder.cpp b/core/fpdfapi/page/cpdf_pageobjectholder.cpp index d7307ab..8aa30ca 100644 --- a/core/fpdfapi/page/cpdf_pageobjectholder.cpp +++ b/core/fpdfapi/page/cpdf_pageobjectholder.cpp
@@ -1,4 +1,4 @@ -// Copyright 2016 PDFium Authors. All rights reserved. +// Copyright 2016 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -16,7 +16,9 @@ #include "core/fpdfapi/parser/cpdf_dictionary.h" #include "core/fpdfapi/parser/cpdf_document.h" #include "core/fxcrt/fx_extension.h" -#include "third_party/base/stl_util.h" +#include "core/fxcrt/stl_util.h" +#include "third_party/base/check.h" +#include "third_party/base/check_op.h" bool GraphicsData::operator<(const GraphicsData& other) const { if (!FXSYS_SafeEQ(fillAlpha, other.fillAlpha)) @@ -32,15 +34,16 @@ return type < other.type; } -CPDF_PageObjectHolder::CPDF_PageObjectHolder(CPDF_Document* pDoc, - CPDF_Dictionary* pDict, - CPDF_Dictionary* pPageResources, - CPDF_Dictionary* pResources) - : m_pPageResources(pPageResources), - m_pResources(pResources), - m_pDict(pDict), +CPDF_PageObjectHolder::CPDF_PageObjectHolder( + CPDF_Document* pDoc, + RetainPtr<CPDF_Dictionary> pDict, + RetainPtr<CPDF_Dictionary> pPageResources, + RetainPtr<CPDF_Dictionary> pResources) + : m_pPageResources(std::move(pPageResources)), + m_pResources(std::move(pResources)), + m_pDict(std::move(pDict)), m_pDocument(pDoc) { - ASSERT(m_pDict); + DCHECK(m_pDict); } CPDF_PageObjectHolder::~CPDF_PageObjectHolder() = default; @@ -51,7 +54,7 @@ void CPDF_PageObjectHolder::StartParse( std::unique_ptr<CPDF_ContentParser> pParser) { - ASSERT(m_ParseState == ParseState::kNotParsed); + DCHECK_EQ(m_ParseState, ParseState::kNotParsed); m_pParser = std::move(pParser); m_ParseState = ParseState::kParsing; } @@ -60,7 +63,7 @@ if (m_ParseState == ParseState::kParsed) return; - ASSERT(m_ParseState == ParseState::kParsing); + DCHECK_EQ(m_ParseState, ParseState::kParsing); if (m_pParser->Continue(pPause)) return; @@ -82,12 +85,40 @@ return dirty_streams; } +absl::optional<ByteString> CPDF_PageObjectHolder::GraphicsMapSearch( + const GraphicsData& gd) { + auto it = m_GraphicsMap.find(gd); + if (it == m_GraphicsMap.end()) + return absl::nullopt; + + return it->second; +} + +void CPDF_PageObjectHolder::GraphicsMapInsert(const GraphicsData& gd, + const ByteString& str) { + m_GraphicsMap[gd] = str; +} + +absl::optional<ByteString> CPDF_PageObjectHolder::FontsMapSearch( + const FontData& fd) { + auto it = m_FontsMap.find(fd); + if (it == m_FontsMap.end()) + return absl::nullopt; + + return it->second; +} + +void CPDF_PageObjectHolder::FontsMapInsert(const FontData& fd, + const ByteString& str) { + m_FontsMap[fd] = str; +} + void CPDF_PageObjectHolder::LoadTransparencyInfo() { - CPDF_Dictionary* pGroup = m_pDict->GetDictFor("Group"); + RetainPtr<const CPDF_Dictionary> pGroup = m_pDict->GetDictFor("Group"); if (!pGroup) return; - if (pGroup->GetStringFor(pdfium::transparency::kGroupSubType) != + if (pGroup->GetByteStringFor(pdfium::transparency::kGroupSubType) != pdfium::transparency::kTransparency) { return; } @@ -98,7 +129,7 @@ CPDF_PageObject* CPDF_PageObjectHolder::GetPageObjectByIndex( size_t index) const { - return pdfium::IndexInBounds(m_PageObjectList, index) + return fxcrt::IndexInBounds(m_PageObjectList, index) ? m_PageObjectList[index].get() : nullptr; } @@ -108,22 +139,21 @@ m_PageObjectList.push_back(std::move(pPageObj)); } -bool CPDF_PageObjectHolder::RemovePageObject(CPDF_PageObject* pPageObj) { - pdfium::FakeUniquePtr<CPDF_PageObject> p(pPageObj); - - auto it = - std::find(std::begin(m_PageObjectList), std::end(m_PageObjectList), p); +std::unique_ptr<CPDF_PageObject> CPDF_PageObjectHolder::RemovePageObject( + CPDF_PageObject* pPageObj) { + auto it = std::find(std::begin(m_PageObjectList), std::end(m_PageObjectList), + fxcrt::MakeFakeUniquePtr(pPageObj)); if (it == std::end(m_PageObjectList)) - return false; + return nullptr; - it->release(); + std::unique_ptr<CPDF_PageObject> result = std::move(*it); m_PageObjectList.erase(it); int32_t content_stream = pPageObj->GetContentStream(); if (content_stream >= 0) m_DirtyStreams.insert(content_stream); - return true; + return result; } bool CPDF_PageObjectHolder::ErasePageObjectAtIndex(size_t index) {
diff --git a/core/fpdfapi/page/cpdf_pageobjectholder.h b/core/fpdfapi/page/cpdf_pageobjectholder.h index b9eff30..629c028 100644 --- a/core/fpdfapi/page/cpdf_pageobjectholder.h +++ b/core/fpdfapi/page/cpdf_pageobjectholder.h
@@ -1,4 +1,4 @@ -// Copyright 2016 PDFium Authors. All rights reserved. +// Copyright 2016 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -7,24 +7,28 @@ #ifndef CORE_FPDFAPI_PAGE_CPDF_PAGEOBJECTHOLDER_H_ #define CORE_FPDFAPI_PAGE_CPDF_PAGEOBJECTHOLDER_H_ +#include <stddef.h> +#include <stdint.h> + #include <deque> #include <map> #include <memory> #include <set> +#include <utility> #include <vector> #include "core/fpdfapi/page/cpdf_transparency.h" +#include "core/fpdfapi/parser/cpdf_dictionary.h" +#include "core/fxcrt/bytestring.h" #include "core/fxcrt/fx_coordinates.h" -#include "core/fxcrt/fx_string.h" -#include "core/fxcrt/fx_system.h" +#include "core/fxcrt/retain_ptr.h" #include "core/fxcrt/unowned_ptr.h" -#include "core/fxge/fx_dib.h" +#include "core/fxge/dib/fx_dib.h" +#include "third_party/abseil-cpp/absl/types/optional.h" class CPDF_ContentParser; -class CPDF_Dictionary; class CPDF_Document; class CPDF_PageObject; -class CPDF_Stream; class PauseIndicatorIface; // These structs are used to keep track of resources that have already been @@ -53,9 +57,9 @@ std::deque<std::unique_ptr<CPDF_PageObject>>::const_iterator; CPDF_PageObjectHolder(CPDF_Document* pDoc, - CPDF_Dictionary* pDict, - CPDF_Dictionary* pPageResources, - CPDF_Dictionary* pResources); + RetainPtr<CPDF_Dictionary> pDict, + RetainPtr<CPDF_Dictionary> pPageResources, + RetainPtr<CPDF_Dictionary> pResources); virtual ~CPDF_PageObjectHolder(); virtual bool IsPage() const; @@ -64,13 +68,26 @@ void ContinueParse(PauseIndicatorIface* pPause); ParseState GetParseState() const { return m_ParseState; } - CPDF_Document* GetDocument() const { return m_pDocument.Get(); } - - CPDF_Dictionary* GetDict() const { return m_pDict.Get(); } + CPDF_Document* GetDocument() const { return m_pDocument; } + RetainPtr<const CPDF_Dictionary> GetDict() const { return m_pDict; } + RetainPtr<CPDF_Dictionary> GetMutableDict() { return m_pDict; } + RetainPtr<const CPDF_Dictionary> GetResources() const { return m_pResources; } + RetainPtr<CPDF_Dictionary> GetMutableResources() { return m_pResources; } + void SetResources(RetainPtr<CPDF_Dictionary> pDict) { + m_pResources = std::move(pDict); + } + RetainPtr<const CPDF_Dictionary> GetPageResources() const { + return m_pPageResources; + } + RetainPtr<CPDF_Dictionary> GetMutablePageResources() { + return m_pPageResources; + } size_t GetPageObjectCount() const { return m_PageObjectList.size(); } CPDF_PageObject* GetPageObjectByIndex(size_t index) const; void AppendPageObject(std::unique_ptr<CPDF_PageObject> pPageObj); - bool RemovePageObject(CPDF_PageObject* pPageObj); + + // Remove `pPageObj` if present, and transfer ownership to the caller. + std::unique_ptr<CPDF_PageObject> RemovePageObject(CPDF_PageObject* pPageObj); bool ErasePageObjectAtIndex(size_t index); iterator begin() { return m_PageObjectList.begin(); } @@ -96,14 +113,19 @@ bool HasDirtyStreams() const { return !m_DirtyStreams.empty(); } std::set<int32_t> TakeDirtyStreams(); - RetainPtr<CPDF_Dictionary> m_pPageResources; - RetainPtr<CPDF_Dictionary> m_pResources; - std::map<GraphicsData, ByteString> m_GraphicsMap; - std::map<FontData, ByteString> m_FontsMap; + absl::optional<ByteString> GraphicsMapSearch(const GraphicsData& gd); + void GraphicsMapInsert(const GraphicsData& gd, const ByteString& str); + + absl::optional<ByteString> FontsMapSearch(const FontData& fd); + void FontsMapInsert(const FontData& fd, const ByteString& str); protected: void LoadTransparencyInfo(); + RetainPtr<CPDF_Dictionary> m_pPageResources; + RetainPtr<CPDF_Dictionary> m_pResources; + std::map<GraphicsData, ByteString> m_GraphicsMap; + std::map<FontData, ByteString> m_FontsMap; CFX_FloatRect m_BBox; CPDF_Transparency m_Transparency;
diff --git a/core/fpdfapi/page/cpdf_pageobjectholder_unittest.cpp b/core/fpdfapi/page/cpdf_pageobjectholder_unittest.cpp index 7760256..c599752 100644 --- a/core/fpdfapi/page/cpdf_pageobjectholder_unittest.cpp +++ b/core/fpdfapi/page/cpdf_pageobjectholder_unittest.cpp
@@ -1,13 +1,22 @@ -// Copyright 2018 PDFium Authors. All rights reserved. +// Copyright 2018 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "core/fpdfapi/page/cpdf_pageobjectholder.h" -#include <limits> +#include <math.h> +#include <algorithm> +#include <limits> +#include <vector> + +#include "core/fxcrt/fx_extension.h" #include "testing/gtest/include/gtest/gtest.h" +bool SafeCompare(const float& x, const float& y) { + return FXSYS_SafeLT(x, y); +} + // See https://crbug.com/852273 TEST(CPDFPageObjectHolder, GraphicsDataAsKey) { const float fMin = std::numeric_limits<float>::min(); @@ -23,6 +32,14 @@ } } + // Validate the documented sort order. + std::vector<float> data = {fMax, fInf, fNan, fMin}; + std::sort(data.begin(), data.end(), SafeCompare); + EXPECT_EQ(data[0], fMin); + EXPECT_EQ(data[1], fMax); + EXPECT_EQ(data[2], fInf); + EXPECT_EQ(isnan(data[3]), isnan(fNan)); + std::map<GraphicsData, int> graphics_map; // Insert in reverse index permuted order.
diff --git a/core/fpdfapi/page/cpdf_path.cpp b/core/fpdfapi/page/cpdf_path.cpp index a07bb6a..cec8175 100644 --- a/core/fpdfapi/page/cpdf_path.cpp +++ b/core/fpdfapi/page/cpdf_path.cpp
@@ -1,4 +1,4 @@ -// Copyright 2016 PDFium Authors. All rights reserved. +// Copyright 2016 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -12,7 +12,7 @@ CPDF_Path::~CPDF_Path() = default; -const std::vector<FX_PATHPOINT>& CPDF_Path::GetPoints() const { +const std::vector<CFX_Path::Point>& CPDF_Path::GetPoints() const { return m_Ref.GetObject()->GetPoints(); } @@ -28,9 +28,10 @@ return m_Ref.GetObject()->GetBoundingBox(); } -CFX_FloatRect CPDF_Path::GetBoundingBox(float line_width, - float miter_limit) const { - return m_Ref.GetObject()->GetBoundingBox(line_width, miter_limit); +CFX_FloatRect CPDF_Path::GetBoundingBoxForStrokePath(float line_width, + float miter_limit) const { + return m_Ref.GetObject()->GetBoundingBoxForStrokePath(line_width, + miter_limit); } bool CPDF_Path::IsRect() const { @@ -41,8 +42,8 @@ m_Ref.GetPrivateCopy()->Transform(matrix); } -void CPDF_Path::Append(const CFX_PathData* pData, const CFX_Matrix* pMatrix) { - m_Ref.GetPrivateCopy()->Append(pData, pMatrix); +void CPDF_Path::Append(const CFX_Path& path, const CFX_Matrix* pMatrix) { + m_Ref.GetPrivateCopy()->Append(path, pMatrix); } void CPDF_Path::AppendFloatRect(const CFX_FloatRect& rect) { @@ -54,9 +55,15 @@ } void CPDF_Path::AppendPoint(const CFX_PointF& point, - FXPT_TYPE type, - bool close) { - CFX_PathData data; - data.AppendPoint(point, type, close); - Append(&data, nullptr); + CFX_Path::Point::Type type) { + CFX_Path data; + data.AppendPoint(point, type); + Append(data, nullptr); +} + +void CPDF_Path::AppendPointAndClose(const CFX_PointF& point, + CFX_Path::Point::Type type) { + CFX_Path data; + data.AppendPointAndClose(point, type); + Append(data, nullptr); }
diff --git a/core/fpdfapi/page/cpdf_path.h b/core/fpdfapi/page/cpdf_path.h index 48f5634..f901f50 100644 --- a/core/fpdfapi/page/cpdf_path.h +++ b/core/fpdfapi/page/cpdf_path.h
@@ -1,4 +1,4 @@ -// Copyright 2016 PDFium Authors. All rights reserved. +// Copyright 2016 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -9,9 +9,8 @@ #include <vector> -#include "core/fxcrt/fx_system.h" #include "core/fxcrt/shared_copy_on_write.h" -#include "core/fxge/cfx_pathdata.h" +#include "core/fxge/cfx_path.h" class CPDF_Path { public: @@ -22,26 +21,28 @@ void Emplace() { m_Ref.Emplace(); } bool HasRef() const { return !!m_Ref; } - const std::vector<FX_PATHPOINT>& GetPoints() const; + const std::vector<CFX_Path::Point>& GetPoints() const; void ClosePath(); CFX_PointF GetPoint(int index) const; CFX_FloatRect GetBoundingBox() const; - CFX_FloatRect GetBoundingBox(float line_width, float miter_limit) const; + CFX_FloatRect GetBoundingBoxForStrokePath(float line_width, + float miter_limit) const; bool IsRect() const; void Transform(const CFX_Matrix& matrix); - void Append(const CFX_PathData* pData, const CFX_Matrix* pMatrix); + void Append(const CFX_Path& path, const CFX_Matrix* pMatrix); void AppendFloatRect(const CFX_FloatRect& rect); void AppendRect(float left, float bottom, float right, float top); - void AppendPoint(const CFX_PointF& point, FXPT_TYPE type, bool close); + void AppendPoint(const CFX_PointF& point, CFX_Path::Point::Type type); + void AppendPointAndClose(const CFX_PointF& point, CFX_Path::Point::Type type); // TODO(tsepez): Remove when all access thru this class. - const CFX_PathData* GetObject() const { return m_Ref.GetObject(); } + const CFX_Path* GetObject() const { return m_Ref.GetObject(); } private: - SharedCopyOnWrite<CFX_RetainablePathData> m_Ref; + SharedCopyOnWrite<CFX_RetainablePath> m_Ref; }; #endif // CORE_FPDFAPI_PAGE_CPDF_PATH_H_
diff --git a/core/fpdfapi/page/cpdf_pathobject.cpp b/core/fpdfapi/page/cpdf_pathobject.cpp index eafbe77..b5e7469 100644 --- a/core/fpdfapi/page/cpdf_pathobject.cpp +++ b/core/fpdfapi/page/cpdf_pathobject.cpp
@@ -1,4 +1,4 @@ -// Copyright 2016 PDFium Authors. All rights reserved. +// Copyright 2016 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -14,7 +14,7 @@ CPDF_PathObject::~CPDF_PathObject() = default; CPDF_PageObject::Type CPDF_PathObject::GetType() const { - return PATH; + return Type::kPath; } void CPDF_PathObject::Transform(const CFX_Matrix& matrix) { @@ -41,7 +41,8 @@ CFX_FloatRect rect; float width = m_GraphState.GetLineWidth(); if (m_bStroke && width != 0) { - rect = m_Path.GetBoundingBox(width, m_GraphState.GetMiterLimit()); + rect = + m_Path.GetBoundingBoxForStrokePath(width, m_GraphState.GetMiterLimit()); } else { rect = m_Path.GetBoundingBox(); } @@ -51,3 +52,8 @@ rect.Inflate(0.5f, 0.5f); SetRect(rect); } + +void CPDF_PathObject::SetPathMatrix(const CFX_Matrix& matrix) { + m_Matrix = matrix; + CalcBoundingBox(); +}
diff --git a/core/fpdfapi/page/cpdf_pathobject.h b/core/fpdfapi/page/cpdf_pathobject.h index 889d8a6..a0b19cb 100644 --- a/core/fpdfapi/page/cpdf_pathobject.h +++ b/core/fpdfapi/page/cpdf_pathobject.h
@@ -1,4 +1,4 @@ -// Copyright 2016 PDFium Authors. All rights reserved. +// Copyright 2016 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -7,11 +7,12 @@ #ifndef CORE_FPDFAPI_PAGE_CPDF_PATHOBJECT_H_ #define CORE_FPDFAPI_PAGE_CPDF_PATHOBJECT_H_ +#include <stdint.h> + #include "core/fpdfapi/page/cpdf_pageobject.h" #include "core/fpdfapi/page/cpdf_path.h" #include "core/fxcrt/fx_coordinates.h" -#include "core/fxcrt/fx_system.h" -#include "core/fxge/render_defines.h" +#include "core/fxge/cfx_fillrenderoptions.h" class CPDF_PathObject final : public CPDF_PageObject { public: @@ -31,26 +32,41 @@ bool stroke() const { return m_bStroke; } void set_stroke(bool stroke) { m_bStroke = stroke; } - // Layering, avoid caller knowledge of FXFILL_ values. - bool has_no_filltype() const { return m_FillType == 0; } - bool has_winding_filltype() const { return m_FillType == FXFILL_WINDING; } - bool has_alternate_filltype() const { return m_FillType == FXFILL_ALTERNATE; } - void set_no_filltype() { m_FillType = 0; } - void set_winding_filltype() { m_FillType = FXFILL_WINDING; } - void set_alternate_filltype() { m_FillType = FXFILL_ALTERNATE; } + // Layering, avoid caller knowledge of CFX_FillRenderOptions::FillType values. + bool has_no_filltype() const { + return m_FillType == CFX_FillRenderOptions::FillType::kNoFill; + } + bool has_winding_filltype() const { + return m_FillType == CFX_FillRenderOptions::FillType::kWinding; + } + bool has_alternate_filltype() const { + return m_FillType == CFX_FillRenderOptions::FillType::kEvenOdd; + } + void set_no_filltype() { + m_FillType = CFX_FillRenderOptions::FillType::kNoFill; + } + void set_winding_filltype() { + m_FillType = CFX_FillRenderOptions::FillType::kWinding; + } + void set_alternate_filltype() { + m_FillType = CFX_FillRenderOptions::FillType::kEvenOdd; + } - int filltype() const { return m_FillType; } - void set_filltype(int filltype) { m_FillType = filltype; } + CFX_FillRenderOptions::FillType filltype() const { return m_FillType; } + void set_filltype(CFX_FillRenderOptions::FillType fill_type) { + m_FillType = fill_type; + } CPDF_Path& path() { return m_Path; } const CPDF_Path& path() const { return m_Path; } const CFX_Matrix& matrix() const { return m_Matrix; } - void set_matrix(const CFX_Matrix& matrix) { m_Matrix = matrix; } + void SetPathMatrix(const CFX_Matrix& matrix); private: bool m_bStroke = false; - int m_FillType = 0; + CFX_FillRenderOptions::FillType m_FillType = + CFX_FillRenderOptions::FillType::kNoFill; CPDF_Path m_Path; CFX_Matrix m_Matrix; };
diff --git a/core/fpdfapi/page/cpdf_pattern.cpp b/core/fpdfapi/page/cpdf_pattern.cpp index 36ecc98..297c77a 100644 --- a/core/fpdfapi/page/cpdf_pattern.cpp +++ b/core/fpdfapi/page/cpdf_pattern.cpp
@@ -1,4 +1,4 @@ -// Copyright 2016 PDFium Authors. All rights reserved. +// Copyright 2016 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -6,14 +6,19 @@ #include "core/fpdfapi/page/cpdf_pattern.h" +#include <utility> + #include "core/fpdfapi/parser/cpdf_dictionary.h" +#include "third_party/base/check.h" CPDF_Pattern::CPDF_Pattern(CPDF_Document* pDoc, - CPDF_Object* pObj, + RetainPtr<CPDF_Object> pObj, const CFX_Matrix& parentMatrix) - : m_pDocument(pDoc), m_pPatternObj(pObj), m_ParentMatrix(parentMatrix) { - ASSERT(m_pDocument); - ASSERT(m_pPatternObj); + : m_pDocument(pDoc), + m_pPatternObj(std::move(pObj)), + m_ParentMatrix(parentMatrix) { + DCHECK(m_pDocument); + DCHECK(m_pPatternObj); } CPDF_Pattern::~CPDF_Pattern() = default; @@ -27,6 +32,6 @@ } void CPDF_Pattern::SetPatternToFormMatrix() { - const CPDF_Dictionary* pDict = pattern_obj()->GetDict(); + RetainPtr<const CPDF_Dictionary> pDict = pattern_obj()->GetDict(); m_Pattern2Form = pDict->GetMatrixFor("Matrix") * m_ParentMatrix; }
diff --git a/core/fpdfapi/page/cpdf_pattern.h b/core/fpdfapi/page/cpdf_pattern.h index 7e3eb7b..cd535b1 100644 --- a/core/fpdfapi/page/cpdf_pattern.h +++ b/core/fpdfapi/page/cpdf_pattern.h
@@ -1,4 +1,4 @@ -// Copyright 2016 PDFium Authors. All rights reserved. +// Copyright 2016 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -7,14 +7,13 @@ #ifndef CORE_FPDFAPI_PAGE_CPDF_PATTERN_H_ #define CORE_FPDFAPI_PAGE_CPDF_PATTERN_H_ +#include "core/fpdfapi/parser/cpdf_object.h" #include "core/fxcrt/fx_coordinates.h" -#include "core/fxcrt/fx_system.h" #include "core/fxcrt/observed_ptr.h" #include "core/fxcrt/retain_ptr.h" #include "core/fxcrt/unowned_ptr.h" class CPDF_Document; -class CPDF_Object; class CPDF_ShadingPattern; class CPDF_TilingPattern; @@ -28,17 +27,18 @@ virtual CPDF_TilingPattern* AsTilingPattern(); virtual CPDF_ShadingPattern* AsShadingPattern(); - // All the getters that return pointers return non-NULL pointers. - CPDF_Document* document() const { return m_pDocument.Get(); } - CPDF_Object* pattern_obj() const { return m_pPatternObj.Get(); } const CFX_Matrix& pattern_to_form() const { return m_Pattern2Form; } - const CFX_Matrix& parent_matrix() const { return m_ParentMatrix; } protected: CPDF_Pattern(CPDF_Document* pDoc, - CPDF_Object* pObj, + RetainPtr<CPDF_Object> pObj, const CFX_Matrix& parentMatrix); + // All the getters that return pointers return non-NULL pointers. + CPDF_Document* document() const { return m_pDocument; } + RetainPtr<CPDF_Object> pattern_obj() const { return m_pPatternObj; } + const CFX_Matrix& parent_matrix() const { return m_ParentMatrix; } + void SetPatternToFormMatrix(); private:
diff --git a/core/fpdfapi/page/cpdf_patterncs.cpp b/core/fpdfapi/page/cpdf_patterncs.cpp index 1c5dc6c..7abc0b2 100644 --- a/core/fpdfapi/page/cpdf_patterncs.cpp +++ b/core/fpdfapi/page/cpdf_patterncs.cpp
@@ -1,4 +1,4 @@ -// Copyright 2014 PDFium Authors. All rights reserved. +// Copyright 2014 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -9,9 +9,9 @@ #include "core/fpdfapi/page/cpdf_docpagedata.h" #include "core/fpdfapi/parser/cpdf_array.h" #include "core/fpdfapi/parser/cpdf_document.h" +#include "third_party/base/notreached.h" -CPDF_PatternCS::CPDF_PatternCS(CPDF_Document* pDoc) - : CPDF_ColorSpace(pDoc, PDFCS_PATTERN) {} +CPDF_PatternCS::CPDF_PatternCS() : CPDF_BasedCS(Family::kPattern) {} CPDF_PatternCS::~CPDF_PatternCS() = default; @@ -22,16 +22,17 @@ uint32_t CPDF_PatternCS::v_Load(CPDF_Document* pDoc, const CPDF_Array* pArray, std::set<const CPDF_Object*>* pVisited) { - const CPDF_Object* pBaseCS = pArray->GetDirectObjectAt(1); - if (pBaseCS == m_pArray) + RetainPtr<const CPDF_Object> pBaseCS = pArray->GetDirectObjectAt(1); + if (HasSameArray(pBaseCS.Get())) return 0; auto* pDocPageData = CPDF_DocPageData::FromDocument(pDoc); - m_pBaseCS = pDocPageData->GetColorSpaceGuarded(pBaseCS, nullptr, pVisited); + m_pBaseCS = + pDocPageData->GetColorSpaceGuarded(pBaseCS.Get(), nullptr, pVisited); if (!m_pBaseCS) return 1; - if (m_pBaseCS->GetFamily() == PDFCS_PATTERN) + if (m_pBaseCS->GetFamily() == Family::kPattern) return 0; if (m_pBaseCS->CountComponents() > kMaxPatternColorComps) @@ -40,16 +41,11 @@ return m_pBaseCS->CountComponents() + 1; } -bool CPDF_PatternCS::GetRGB(const float* pBuf, +bool CPDF_PatternCS::GetRGB(pdfium::span<const float> pBuf, float* R, float* G, float* B) const { - NOTREACHED(); - return false; -} - -CPDF_PatternCS* CPDF_PatternCS::AsPatternCS() { - return this; + NOTREACHED_NORETURN(); } const CPDF_PatternCS* CPDF_PatternCS::AsPatternCS() const { @@ -60,7 +56,7 @@ float* R, float* G, float* B) const { - if (m_pBaseCS && m_pBaseCS->GetRGB(value.GetComps().data(), R, G, B)) + if (m_pBaseCS && m_pBaseCS->GetRGB(value.GetComps(), R, G, B)) return true; *R = 0.75f;
diff --git a/core/fpdfapi/page/cpdf_patterncs.h b/core/fpdfapi/page/cpdf_patterncs.h index b6b46f6..896a95c 100644 --- a/core/fpdfapi/page/cpdf_patterncs.h +++ b/core/fpdfapi/page/cpdf_patterncs.h
@@ -1,4 +1,4 @@ -// Copyright 2017 PDFium Authors. All rights reserved. +// Copyright 2017 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -9,16 +9,14 @@ #include <set> -#include "core/fpdfapi/page/cpdf_colorspace.h" +#include "core/fpdfapi/page/cpdf_basedcs.h" #include "core/fxcrt/retain_ptr.h" class CPDF_Document; -class CPDF_PatternCS final : public CPDF_ColorSpace { +class CPDF_PatternCS final : public CPDF_BasedCS { public: - template <typename T, typename... Args> - friend RetainPtr<T> pdfium::MakeRetain(Args&&... args); - + CONSTRUCT_VIA_MAKE_RETAIN; ~CPDF_PatternCS() override; // Called for the stock pattern, since it is not initialized via @@ -26,21 +24,22 @@ void InitializeStockPattern(); // CPDF_ColorSpace: - bool GetRGB(const float* pBuf, float* R, float* G, float* B) const override; - bool GetPatternRGB(const PatternValue& value, - float* R, - float* G, - float* B) const override; - CPDF_PatternCS* AsPatternCS() override; + bool GetRGB(pdfium::span<const float> pBuf, + float* R, + float* G, + float* B) const override; const CPDF_PatternCS* AsPatternCS() const override; uint32_t v_Load(CPDF_Document* pDoc, const CPDF_Array* pArray, std::set<const CPDF_Object*>* pVisited) override; - private: - explicit CPDF_PatternCS(CPDF_Document* pDoc); + bool GetPatternRGB(const PatternValue& value, + float* R, + float* G, + float* B) const; - RetainPtr<CPDF_ColorSpace> m_pBaseCS; + private: + CPDF_PatternCS(); }; #endif // CORE_FPDFAPI_PAGE_CPDF_PATTERNCS_H_
diff --git a/core/fpdfapi/page/cpdf_psengine.cpp b/core/fpdfapi/page/cpdf_psengine.cpp index 98f5c47..da7b00d 100644 --- a/core/fpdfapi/page/cpdf_psengine.cpp +++ b/core/fpdfapi/page/cpdf_psengine.cpp
@@ -1,4 +1,4 @@ -// Copyright 2017 PDFium Authors. All rights reserved. +// Copyright 2017 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -6,21 +6,24 @@ #include "core/fpdfapi/page/cpdf_psengine.h" +#include <math.h> + #include <algorithm> -#include <cmath> #include <limits> #include <utility> #include "core/fpdfapi/parser/cpdf_simple_parser.h" #include "core/fxcrt/fx_safe_types.h" #include "core/fxcrt/fx_string.h" -#include "third_party/base/logging.h" -#include "third_party/base/ptr_util.h" +#include "third_party/base/check.h" +#include "third_party/base/check_op.h" +#include "third_party/base/notreached.h" namespace { struct PDF_PSOpName { - const char* name; + // Inline string data reduces size for small strings. + const char name[9]; PDF_PSOP op; }; @@ -72,7 +75,7 @@ // Round half up is a nearest integer round with half-way numbers always rounded // up. Example: -5.5 rounds to -5. float RoundHalfUp(float f) { - if (std::isnan(f)) + if (isnan(f)) return 0; if (f > std::numeric_limits<float>::max() - 0.5f) return std::numeric_limits<float>::max(); @@ -82,44 +85,47 @@ } // namespace CPDF_PSOP::CPDF_PSOP() - : m_op(PSOP_PROC), m_value(0), m_proc(pdfium::MakeUnique<CPDF_PSProc>()) {} + : m_op(PSOP_PROC), m_value(0), m_proc(std::make_unique<CPDF_PSProc>()) {} CPDF_PSOP::CPDF_PSOP(PDF_PSOP op) : m_op(op), m_value(0) { - ASSERT(m_op != PSOP_CONST); - ASSERT(m_op != PSOP_PROC); + DCHECK(m_op != PSOP_CONST); + DCHECK(m_op != PSOP_PROC); } CPDF_PSOP::CPDF_PSOP(float value) : m_op(PSOP_CONST), m_value(value) {} -CPDF_PSOP::~CPDF_PSOP() {} +CPDF_PSOP::~CPDF_PSOP() = default; + +bool CPDF_PSOP::Parse(CPDF_SimpleParser* parser, int depth) { + CHECK_EQ(m_op, PSOP_PROC); + return m_proc->Parse(parser, depth); +} + +void CPDF_PSOP::Execute(CPDF_PSEngine* pEngine) { + CHECK_EQ(m_op, PSOP_PROC); + m_proc->Execute(pEngine); +} float CPDF_PSOP::GetFloatValue() const { if (m_op == PSOP_CONST) return m_value; - NOTREACHED(); - return 0; -} - -CPDF_PSProc* CPDF_PSOP::GetProc() const { - if (m_op == PSOP_PROC) - return m_proc.get(); - NOTREACHED(); - return nullptr; + NOTREACHED_NORETURN(); } bool CPDF_PSEngine::Execute() { return m_MainProc.Execute(this); } -CPDF_PSProc::CPDF_PSProc() {} -CPDF_PSProc::~CPDF_PSProc() {} +CPDF_PSProc::CPDF_PSProc() = default; + +CPDF_PSProc::~CPDF_PSProc() = default; bool CPDF_PSProc::Parse(CPDF_SimpleParser* parser, int depth) { if (depth > kMaxDepth) return false; - while (1) { + while (true) { ByteStringView word = parser->GetWord(); if (word.IsEmpty()) return false; @@ -128,8 +134,8 @@ return true; if (word == "{") { - m_Operators.push_back(pdfium::MakeUnique<CPDF_PSOP>()); - if (!m_Operators.back()->GetProc()->Parse(parser, depth + 1)) + m_Operators.push_back(std::make_unique<CPDF_PSOP>()); + if (!m_Operators.back()->Parse(parser, depth + 1)) return false; continue; } @@ -154,14 +160,14 @@ return false; if (pEngine->PopInt()) - m_Operators[i - 1]->GetProc()->Execute(pEngine); + m_Operators[i - 1]->Execute(pEngine); } else if (op == PSOP_IFELSE) { if (i < 2 || m_Operators[i - 1]->GetOp() != PSOP_PROC || m_Operators[i - 2]->GetOp() != PSOP_PROC) { return false; } size_t offset = pEngine->PopInt() ? 2 : 1; - m_Operators[i - offset]->GetProc()->Execute(pEngine); + m_Operators[i - offset]->Execute(pEngine); } else { pEngine->DoOperator(op); } @@ -180,9 +186,9 @@ return name.name < word; }); if (pFound != std::end(kPsOpNames) && pFound->name == word) - m_Operators.push_back(pdfium::MakeUnique<CPDF_PSOP>(pFound->op)); + m_Operators.push_back(std::make_unique<CPDF_PSOP>(pFound->op)); else - m_Operators.push_back(pdfium::MakeUnique<CPDF_PSOP>(StringToFloat(word))); + m_Operators.push_back(std::make_unique<CPDF_PSOP>(StringToFloat(word))); } CPDF_PSEngine::CPDF_PSEngine() = default; @@ -232,7 +238,7 @@ case PSOP_DIV: d2 = Pop(); d1 = Pop(); - Push(d1 / d2); + Push(d2 ? d1 / d2 : 0); break; case PSOP_IDIV: i2 = PopInt(); @@ -286,16 +292,16 @@ break; case PSOP_SIN: d1 = Pop(); - Push(sin(d1 * FX_PI / 180.0f)); + Push(sin(d1 * FXSYS_PI / 180.0f)); break; case PSOP_COS: d1 = Pop(); - Push(cos(d1 * FX_PI / 180.0f)); + Push(cos(d1 * FXSYS_PI / 180.0f)); break; case PSOP_ATAN: d2 = Pop(); d1 = Pop(); - d1 = atan2(d1, d2) * 180.0 / FX_PI; + d1 = atan2(d1, d2) * 180.0 / FXSYS_PI; if (d1 < 0) { d1 += 360; } @@ -304,7 +310,7 @@ case PSOP_EXP: d2 = Pop(); d1 = Pop(); - Push(FXSYS_pow(d1, d2)); + Push(powf(d1, d2)); break; case PSOP_LN: d1 = Pop();
diff --git a/core/fpdfapi/page/cpdf_psengine.h b/core/fpdfapi/page/cpdf_psengine.h index 3db8db7..d7f6f7e 100644 --- a/core/fpdfapi/page/cpdf_psengine.h +++ b/core/fpdfapi/page/cpdf_psengine.h
@@ -1,4 +1,4 @@ -// Copyright 2016 PDFium Authors. All rights reserved. +// Copyright 2016 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -7,11 +7,13 @@ #ifndef CORE_FPDFAPI_PAGE_CPDF_PSENGINE_H_ #define CORE_FPDFAPI_PAGE_CPDF_PSENGINE_H_ +#include <stddef.h> +#include <stdint.h> + #include <memory> #include <vector> -#include "core/fxcrt/fx_string.h" -#include "core/fxcrt/fx_system.h" +#include "core/fxcrt/bytestring.h" #include "third_party/base/span.h" class CPDF_PSEngine; @@ -72,8 +74,9 @@ explicit CPDF_PSOP(float value); ~CPDF_PSOP(); + bool Parse(CPDF_SimpleParser* parser, int depth); + void Execute(CPDF_PSEngine* pEngine); float GetFloatValue() const; - CPDF_PSProc* GetProc() const; PDF_PSOP GetOp() const { return m_op; } private: @@ -98,7 +101,7 @@ } private: - static const int kMaxDepth = 128; + static constexpr int kMaxDepth = 128; void AddOperator(ByteStringView word); @@ -124,7 +127,7 @@ uint32_t m_StackCount = 0; CPDF_PSProc m_MainProc; - float m_Stack[kPSEngineStackSize]; + float m_Stack[kPSEngineStackSize] = {}; }; #endif // CORE_FPDFAPI_PAGE_CPDF_PSENGINE_H_
diff --git a/core/fpdfapi/page/cpdf_psengine_unittest.cpp b/core/fpdfapi/page/cpdf_psengine_unittest.cpp index a922de1..ae458b3 100644 --- a/core/fpdfapi/page/cpdf_psengine_unittest.cpp +++ b/core/fpdfapi/page/cpdf_psengine_unittest.cpp
@@ -1,14 +1,24 @@ -// Copyright 2017 PDFium Authors. All rights reserved. +// Copyright 2017 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include "core/fpdfapi/page/cpdf_psengine.h" + +#include <iterator> #include <limits> -#include "core/fpdfapi/page/cpdf_psengine.h" #include "testing/gtest/include/gtest/gtest.h" namespace { +float DoOperator0(CPDF_PSEngine* engine, PDF_PSOP op) { + EXPECT_EQ(0u, engine->GetStackSize()); + engine->DoOperator(op); + float ret = engine->Pop(); + EXPECT_EQ(0u, engine->GetStackSize()); + return ret; +} + float DoOperator1(CPDF_PSEngine* engine, float v1, PDF_PSOP op) { EXPECT_EQ(0u, engine->GetStackSize()); engine->Push(v1); @@ -62,7 +72,7 @@ CPDF_PSProc proc; EXPECT_EQ(0U, proc.num_operators()); - for (size_t i = 0; i < FX_ArraySize(kTestData); ++i) { + for (size_t i = 0; i < std::size(kTestData); ++i) { ByteStringView word(kTestData[i].name); proc.AddOperatorForTesting(word); ASSERT_EQ(i + 1, proc.num_operators()); @@ -93,6 +103,17 @@ EXPECT_FLOAT_EQ(5.0f, DoOperator1(&engine, -5, PSOP_ABS)); } +TEST(CPDF_PSEngine, DivByZero) { + CPDF_PSEngine engine; + + // Integer divide by zero is defined as resulting in 0. + EXPECT_FLOAT_EQ(0.0f, DoOperator2(&engine, 100, 0.0, PSOP_IDIV)); + EXPECT_FLOAT_EQ(0.0f, DoOperator2(&engine, 100, 0.0, PSOP_MOD)); + + // floating divide by zero is defined as resulting in 0. + EXPECT_FLOAT_EQ(0.0f, DoOperator2(&engine, 100, 0.0, PSOP_DIV)); +} + TEST(CPDF_PSEngine, Ceiling) { CPDF_PSEngine engine; @@ -184,10 +205,79 @@ // Truncate does not behave according to the PostScript Language Reference for // values beyond the range of integers. This seems to match Acrobat's - // behavior. See https://crbug.com/1314. - float max_int = std::numeric_limits<int>::max(); - EXPECT_FLOAT_EQ(-max_int, - DoOperator1(&engine, max_int * 2.0f, PSOP_TRUNCATE)); + // behavior. See https://crbug.com/pdfium/1314. + float max_int = static_cast<float>(std::numeric_limits<int>::max()); EXPECT_FLOAT_EQ(-max_int, DoOperator1(&engine, max_int * -1.5f, PSOP_TRUNCATE)); } + +TEST(CPDF_PSEngine, Comparisons) { + CPDF_PSEngine engine; + + EXPECT_FLOAT_EQ(1.0f, DoOperator2(&engine, 0.0f, 0.0f, PSOP_EQ)); + EXPECT_FLOAT_EQ(0.0f, DoOperator2(&engine, 0.0f, 1.0f, PSOP_EQ)); + EXPECT_FLOAT_EQ(0.0f, DoOperator2(&engine, 255.0f, 1.0f, PSOP_EQ)); + EXPECT_FLOAT_EQ(0.0f, DoOperator2(&engine, -1.0f, 0.0f, PSOP_EQ)); + + EXPECT_FLOAT_EQ(0.0f, DoOperator2(&engine, 0.0f, 0.0f, PSOP_NE)); + EXPECT_FLOAT_EQ(1.0f, DoOperator2(&engine, 0.0f, 1.0f, PSOP_NE)); + EXPECT_FLOAT_EQ(1.0f, DoOperator2(&engine, 255.0f, 1.0f, PSOP_NE)); + EXPECT_FLOAT_EQ(1.0f, DoOperator2(&engine, -1.0f, 0.0f, PSOP_NE)); + + EXPECT_FLOAT_EQ(0.0f, DoOperator2(&engine, 0.0f, 0.0f, PSOP_GT)); + EXPECT_FLOAT_EQ(0.0f, DoOperator2(&engine, 0.0f, 1.0f, PSOP_GT)); + EXPECT_FLOAT_EQ(1.0f, DoOperator2(&engine, 255.0f, 1.0f, PSOP_GT)); + EXPECT_FLOAT_EQ(0.0f, DoOperator2(&engine, -1.0f, 0.0f, PSOP_GT)); + + EXPECT_FLOAT_EQ(1.0f, DoOperator2(&engine, 0.0f, 0.0f, PSOP_GE)); + EXPECT_FLOAT_EQ(0.0f, DoOperator2(&engine, 0.0f, 1.0f, PSOP_GE)); + EXPECT_FLOAT_EQ(1.0f, DoOperator2(&engine, 255.0f, 1.0f, PSOP_GE)); + EXPECT_FLOAT_EQ(0.0f, DoOperator2(&engine, -1.0f, 0.0f, PSOP_GE)); + + EXPECT_FLOAT_EQ(0.0f, DoOperator2(&engine, 0.0f, 0.0f, PSOP_LT)); + EXPECT_FLOAT_EQ(1.0f, DoOperator2(&engine, 0.0f, 1.0f, PSOP_LT)); + EXPECT_FLOAT_EQ(0.0f, DoOperator2(&engine, 255.0f, 1.0f, PSOP_LT)); + EXPECT_FLOAT_EQ(1.0f, DoOperator2(&engine, -1.0f, 0.0f, PSOP_LT)); + + EXPECT_FLOAT_EQ(1.0f, DoOperator2(&engine, 0.0f, 0.0f, PSOP_LE)); + EXPECT_FLOAT_EQ(1.0f, DoOperator2(&engine, 0.0f, 1.0f, PSOP_LE)); + EXPECT_FLOAT_EQ(0.0f, DoOperator2(&engine, 255.0f, 1.0f, PSOP_LE)); + EXPECT_FLOAT_EQ(1.0f, DoOperator2(&engine, -1.0f, 0.0f, PSOP_LE)); +} + +TEST(CPDF_PSEngine, Logic) { + CPDF_PSEngine engine; + + EXPECT_FLOAT_EQ(1.0f, DoOperator0(&engine, PSOP_TRUE)); + EXPECT_FLOAT_EQ(0.0f, DoOperator0(&engine, PSOP_FALSE)); + + EXPECT_FLOAT_EQ(0.0f, DoOperator2(&engine, 0.0f, 0.0f, PSOP_AND)); + EXPECT_FLOAT_EQ(0.0f, DoOperator2(&engine, 0.0f, 1.0f, PSOP_AND)); + EXPECT_FLOAT_EQ(0.0f, DoOperator2(&engine, 1.0f, 0.0f, PSOP_AND)); + EXPECT_FLOAT_EQ(1.0f, DoOperator2(&engine, 1.0f, 1.0f, PSOP_AND)); + + EXPECT_FLOAT_EQ(0.0f, DoOperator2(&engine, 0.0f, 0.0f, PSOP_OR)); + EXPECT_FLOAT_EQ(1.0f, DoOperator2(&engine, 0.0f, 1.0f, PSOP_OR)); + EXPECT_FLOAT_EQ(1.0f, DoOperator2(&engine, 1.0f, 0.0f, PSOP_OR)); + EXPECT_FLOAT_EQ(1.0f, DoOperator2(&engine, 1.0f, 1.0f, PSOP_OR)); + + EXPECT_FLOAT_EQ(0.0f, DoOperator2(&engine, 0.0f, 0.0f, PSOP_XOR)); + EXPECT_FLOAT_EQ(1.0f, DoOperator2(&engine, 0.0f, 1.0f, PSOP_XOR)); + EXPECT_FLOAT_EQ(1.0f, DoOperator2(&engine, 1.0f, 0.0f, PSOP_XOR)); + EXPECT_FLOAT_EQ(0.0f, DoOperator2(&engine, 1.0f, 1.0f, PSOP_XOR)); + + EXPECT_FLOAT_EQ(1.0f, DoOperator1(&engine, 0.0f, PSOP_NOT)); + EXPECT_FLOAT_EQ(0.0f, DoOperator1(&engine, 1.0f, PSOP_NOT)); +} + +TEST(CPDF_PSEngine, MathFunctions) { + CPDF_PSEngine engine; + + EXPECT_FLOAT_EQ(1.4142135f, DoOperator1(&engine, 2.0f, PSOP_SQRT)); + EXPECT_FLOAT_EQ(0.8660254f, DoOperator1(&engine, 60.0f, PSOP_SIN)); + EXPECT_FLOAT_EQ(0.5f, DoOperator1(&engine, 60.0f, PSOP_COS)); + EXPECT_FLOAT_EQ(45.0f, DoOperator2(&engine, 1.0f, 1.0f, PSOP_ATAN)); + EXPECT_FLOAT_EQ(1000.0f, DoOperator2(&engine, 10.0f, 3.0f, PSOP_EXP)); + EXPECT_FLOAT_EQ(3.0f, DoOperator1(&engine, 1000.0f, PSOP_LOG)); + EXPECT_FLOAT_EQ(2.302585f, DoOperator1(&engine, 10.0f, PSOP_LN)); +}
diff --git a/core/fpdfapi/page/cpdf_psfunc.cpp b/core/fpdfapi/page/cpdf_psfunc.cpp index ffc5053..60ec52b 100644 --- a/core/fpdfapi/page/cpdf_psfunc.cpp +++ b/core/fpdfapi/page/cpdf_psfunc.cpp
@@ -1,4 +1,4 @@ -// Copyright 2017 PDFium Authors. All rights reserved. +// Copyright 2017 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -11,16 +11,17 @@ CPDF_PSFunc::CPDF_PSFunc() : CPDF_Function(Type::kType4PostScript) {} -CPDF_PSFunc::~CPDF_PSFunc() {} +CPDF_PSFunc::~CPDF_PSFunc() = default; -bool CPDF_PSFunc::v_Init(const CPDF_Object* pObj, - std::set<const CPDF_Object*>* pVisited) { - auto pAcc = pdfium::MakeRetain<CPDF_StreamAcc>(pObj->AsStream()); +bool CPDF_PSFunc::v_Init(const CPDF_Object* pObj, VisitedSet* pVisited) { + auto pAcc = + pdfium::MakeRetain<CPDF_StreamAcc>(pdfium::WrapRetain(pObj->AsStream())); pAcc->LoadAllDataFiltered(); return m_PS.Parse(pAcc->GetSpan()); } -bool CPDF_PSFunc::v_Call(const float* inputs, float* results) const { +bool CPDF_PSFunc::v_Call(pdfium::span<const float> inputs, + pdfium::span<float> results) const { m_PS.Reset(); for (uint32_t i = 0; i < m_nInputs; i++) m_PS.Push(inputs[i]);
diff --git a/core/fpdfapi/page/cpdf_psfunc.h b/core/fpdfapi/page/cpdf_psfunc.h index b81c2e7..fd7a7d8 100644 --- a/core/fpdfapi/page/cpdf_psfunc.h +++ b/core/fpdfapi/page/cpdf_psfunc.h
@@ -1,4 +1,4 @@ -// Copyright 2017 PDFium Authors. All rights reserved. +// Copyright 2017 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -7,8 +7,6 @@ #ifndef CORE_FPDFAPI_PAGE_CPDF_PSFUNC_H_ #define CORE_FPDFAPI_PAGE_CPDF_PSFUNC_H_ -#include <set> - #include "core/fpdfapi/page/cpdf_function.h" #include "core/fpdfapi/page/cpdf_psengine.h" @@ -19,10 +17,10 @@ CPDF_PSFunc(); ~CPDF_PSFunc() override; - // CPDF_Function - bool v_Init(const CPDF_Object* pObj, - std::set<const CPDF_Object*>* pVisited) override; - bool v_Call(const float* inputs, float* results) const override; + // CPDF_Function: + bool v_Init(const CPDF_Object* pObj, VisitedSet* pVisited) override; + bool v_Call(pdfium::span<const float> inputs, + pdfium::span<float> results) const override; private: mutable CPDF_PSEngine m_PS; // Pre-initialized scratch space for v_Call().
diff --git a/core/fpdfapi/page/cpdf_sampledfunc.cpp b/core/fpdfapi/page/cpdf_sampledfunc.cpp index c80e16c..0aa28f4 100644 --- a/core/fpdfapi/page/cpdf_sampledfunc.cpp +++ b/core/fpdfapi/page/cpdf_sampledfunc.cpp
@@ -1,4 +1,4 @@ -// Copyright 2017 PDFium Authors. All rights reserved. +// Copyright 2017 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -6,14 +6,16 @@ #include "core/fpdfapi/page/cpdf_sampledfunc.h" +#include <utility> + #include "core/fpdfapi/parser/cpdf_array.h" #include "core/fpdfapi/parser/cpdf_dictionary.h" #include "core/fpdfapi/parser/cpdf_stream.h" #include "core/fpdfapi/parser/cpdf_stream_acc.h" #include "core/fxcrt/cfx_bitstream.h" -#include "core/fxcrt/cfx_fixedbufgrow.h" #include "core/fxcrt/fx_safe_types.h" -#include "third_party/base/stl_util.h" +#include "core/fxcrt/small_buffer.h" +#include "third_party/base/cxx17_backports.h" namespace { @@ -38,16 +40,15 @@ CPDF_SampledFunc::CPDF_SampledFunc() : CPDF_Function(Type::kType0Sampled) {} -CPDF_SampledFunc::~CPDF_SampledFunc() {} +CPDF_SampledFunc::~CPDF_SampledFunc() = default; -bool CPDF_SampledFunc::v_Init(const CPDF_Object* pObj, - std::set<const CPDF_Object*>* pVisited) { - const CPDF_Stream* pStream = pObj->AsStream(); +bool CPDF_SampledFunc::v_Init(const CPDF_Object* pObj, VisitedSet* pVisited) { + RetainPtr<const CPDF_Stream> pStream(pObj->AsStream()); if (!pStream) return false; - const CPDF_Dictionary* pDict = pStream->GetDict(); - const CPDF_Array* pSize = pDict->GetArrayFor("Size"); + RetainPtr<const CPDF_Dictionary> pDict = pStream->GetDict(); + RetainPtr<const CPDF_Array> pSize = pDict->GetArrayFor("Size"); if (!pSize || pSize->IsEmpty()) return false; @@ -57,7 +58,7 @@ FX_SAFE_UINT32 nTotalSampleBits = m_nBitsPerSample; nTotalSampleBits *= m_nOutputs; - const CPDF_Array* pEncode = pDict->GetArrayFor("Encode"); + RetainPtr<const CPDF_Array> pEncode = pDict->GetArrayFor("Encode"); m_EncodeInfo.resize(m_nInputs); for (uint32_t i = 0; i < m_nInputs; i++) { int size = pSize->GetIntegerAt(i); @@ -67,8 +68,8 @@ m_EncodeInfo[i].sizes = size; nTotalSampleBits *= m_EncodeInfo[i].sizes; if (pEncode) { - m_EncodeInfo[i].encode_min = pEncode->GetNumberAt(i * 2); - m_EncodeInfo[i].encode_max = pEncode->GetNumberAt(i * 2 + 1); + m_EncodeInfo[i].encode_min = pEncode->GetFloatAt(i * 2); + m_EncodeInfo[i].encode_max = pEncode->GetFloatAt(i * 2 + 1); } else { m_EncodeInfo[i].encode_min = 0; m_EncodeInfo[i].encode_max = @@ -80,17 +81,17 @@ return false; m_SampleMax = 0xffffffff >> (32 - m_nBitsPerSample); - m_pSampleStream = pdfium::MakeRetain<CPDF_StreamAcc>(pStream); + m_pSampleStream = pdfium::MakeRetain<CPDF_StreamAcc>(std::move(pStream)); m_pSampleStream->LoadAllDataFiltered(); if (nTotalSampleBytes.ValueOrDie() > m_pSampleStream->GetSize()) return false; - const CPDF_Array* pDecode = pDict->GetArrayFor("Decode"); + RetainPtr<const CPDF_Array> pDecode = pDict->GetArrayFor("Decode"); m_DecodeInfo.resize(m_nOutputs); for (uint32_t i = 0; i < m_nOutputs; i++) { if (pDecode) { - m_DecodeInfo[i].decode_min = pDecode->GetNumberAt(2 * i); - m_DecodeInfo[i].decode_max = pDecode->GetNumberAt(2 * i + 1); + m_DecodeInfo[i].decode_min = pDecode->GetFloatAt(2 * i); + m_DecodeInfo[i].decode_max = pDecode->GetFloatAt(2 * i + 1); } else { m_DecodeInfo[i].decode_min = m_Ranges[i * 2]; m_DecodeInfo[i].decode_max = m_Ranges[i * 2 + 1]; @@ -99,12 +100,13 @@ return true; } -bool CPDF_SampledFunc::v_Call(const float* inputs, float* results) const { +bool CPDF_SampledFunc::v_Call(pdfium::span<const float> inputs, + pdfium::span<float> results) const { int pos = 0; - CFX_FixedBufGrow<float, 16> encoded_input_buf(m_nInputs); - float* encoded_input = encoded_input_buf; - CFX_FixedBufGrow<uint32_t, 32> int_buf(m_nInputs * 2); - uint32_t* index = int_buf; + fxcrt::SmallBuffer<float, 16> encoded_input_buf(m_nInputs); + fxcrt::SmallBuffer<uint32_t, 32> int_buf(m_nInputs * 2); + float* encoded_input = encoded_input_buf.data(); + uint32_t* index = int_buf.data(); uint32_t* blocksize = index + m_nInputs; for (uint32_t i = 0; i < m_nInputs; i++) { if (i == 0) @@ -174,7 +176,7 @@ return true; } -#if defined _SKIA_SUPPORT_ || defined _SKIA_SUPPORT_PATHS_ +#if defined(_SKIA_SUPPORT_) RetainPtr<CPDF_StreamAcc> CPDF_SampledFunc::GetSampleStream() const { return m_pSampleStream; }
diff --git a/core/fpdfapi/page/cpdf_sampledfunc.h b/core/fpdfapi/page/cpdf_sampledfunc.h index 520b692..93c81df 100644 --- a/core/fpdfapi/page/cpdf_sampledfunc.h +++ b/core/fpdfapi/page/cpdf_sampledfunc.h
@@ -1,4 +1,4 @@ -// Copyright 2017 PDFium Authors. All rights reserved. +// Copyright 2017 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -7,7 +7,6 @@ #ifndef CORE_FPDFAPI_PAGE_CPDF_SAMPLEDFUNC_H_ #define CORE_FPDFAPI_PAGE_CPDF_SAMPLEDFUNC_H_ -#include <set> #include <vector> #include "core/fpdfapi/page/cpdf_function.h" @@ -31,25 +30,25 @@ CPDF_SampledFunc(); ~CPDF_SampledFunc() override; - // CPDF_Function - bool v_Init(const CPDF_Object* pObj, - std::set<const CPDF_Object*>* pVisited) override; - bool v_Call(const float* inputs, float* results) const override; + // CPDF_Function: + bool v_Init(const CPDF_Object* pObj, VisitedSet* pVisited) override; + bool v_Call(pdfium::span<const float> inputs, + pdfium::span<float> results) const override; const std::vector<SampleEncodeInfo>& GetEncodeInfo() const { return m_EncodeInfo; } uint32_t GetBitsPerSample() const { return m_nBitsPerSample; } -#if defined _SKIA_SUPPORT_ || defined _SKIA_SUPPORT_PATHS_ +#if defined(_SKIA_SUPPORT_) RetainPtr<CPDF_StreamAcc> GetSampleStream() const; #endif private: std::vector<SampleEncodeInfo> m_EncodeInfo; std::vector<SampleDecodeInfo> m_DecodeInfo; - uint32_t m_nBitsPerSample; - uint32_t m_SampleMax; + uint32_t m_nBitsPerSample = 0; + uint32_t m_SampleMax = 0; RetainPtr<CPDF_StreamAcc> m_pSampleStream; };
diff --git a/core/fpdfapi/page/cpdf_shadingobject.cpp b/core/fpdfapi/page/cpdf_shadingobject.cpp index bdaceaa..06d43aa 100644 --- a/core/fpdfapi/page/cpdf_shadingobject.cpp +++ b/core/fpdfapi/page/cpdf_shadingobject.cpp
@@ -1,4 +1,4 @@ -// Copyright 2016 PDFium Authors. All rights reserved. +// Copyright 2016 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -6,18 +6,21 @@ #include "core/fpdfapi/page/cpdf_shadingobject.h" +#include <utility> + #include "core/fpdfapi/page/cpdf_shadingpattern.h" -#include "core/fpdfapi/parser/cpdf_document.h" CPDF_ShadingObject::CPDF_ShadingObject(int32_t content_stream, - CPDF_ShadingPattern* pattern, + RetainPtr<CPDF_ShadingPattern> pattern, const CFX_Matrix& matrix) - : CPDF_PageObject(content_stream), m_pShading(pattern), m_Matrix(matrix) {} + : CPDF_PageObject(content_stream), + m_pShading(std::move(pattern)), + m_Matrix(matrix) {} -CPDF_ShadingObject::~CPDF_ShadingObject() {} +CPDF_ShadingObject::~CPDF_ShadingObject() = default; CPDF_PageObject::Type CPDF_ShadingObject::GetType() const { - return SHADING; + return Type::kShading; } void CPDF_ShadingObject::Transform(const CFX_Matrix& matrix) { @@ -25,12 +28,11 @@ m_ClipPath.Transform(matrix); m_Matrix.Concat(matrix); - if (m_ClipPath.HasRef()) { + if (m_ClipPath.HasRef()) CalcBoundingBox(); - return; - } - - SetRect(matrix.TransformRect(GetRect())); + else + SetRect(matrix.TransformRect(GetRect())); + SetDirty(true); } bool CPDF_ShadingObject::IsShading() const {
diff --git a/core/fpdfapi/page/cpdf_shadingobject.h b/core/fpdfapi/page/cpdf_shadingobject.h index 072a025..78aba1f 100644 --- a/core/fpdfapi/page/cpdf_shadingobject.h +++ b/core/fpdfapi/page/cpdf_shadingobject.h
@@ -1,4 +1,4 @@ -// Copyright 2016 PDFium Authors. All rights reserved. +// Copyright 2016 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -16,7 +16,7 @@ class CPDF_ShadingObject final : public CPDF_PageObject { public: CPDF_ShadingObject(int32_t content_stream, - CPDF_ShadingPattern* pattern, + RetainPtr<CPDF_ShadingPattern> pattern, const CFX_Matrix& matrix); ~CPDF_ShadingObject() override;
diff --git a/core/fpdfapi/page/cpdf_shadingpattern.cpp b/core/fpdfapi/page/cpdf_shadingpattern.cpp index 69696ac..9d26ba9 100644 --- a/core/fpdfapi/page/cpdf_shadingpattern.cpp +++ b/core/fpdfapi/page/cpdf_shadingpattern.cpp
@@ -1,4 +1,4 @@ -// Copyright 2016 PDFium Authors. All rights reserved. +// Copyright 2016 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -7,6 +7,7 @@ #include "core/fpdfapi/page/cpdf_shadingpattern.h" #include <algorithm> +#include <utility> #include "core/fpdfapi/page/cpdf_docpagedata.h" #include "core/fpdfapi/page/cpdf_function.h" @@ -16,6 +17,8 @@ #include "core/fpdfapi/parser/cpdf_object.h" #include "core/fpdfapi/parser/cpdf_stream.h" #include "core/fxcrt/fx_safe_types.h" +#include "third_party/base/check.h" +#include "third_party/base/notreached.h" namespace { @@ -28,11 +31,12 @@ } // namespace CPDF_ShadingPattern::CPDF_ShadingPattern(CPDF_Document* pDoc, - CPDF_Object* pPatternObj, + RetainPtr<CPDF_Object> pPatternObj, bool bShading, const CFX_Matrix& parentMatrix) - : CPDF_Pattern(pDoc, pPatternObj, parentMatrix), m_bShading(bShading) { - ASSERT(document()); + : CPDF_Pattern(pDoc, std::move(pPatternObj), parentMatrix), + m_bShading(bShading) { + DCHECK(document()); if (!bShading) SetPatternToFormMatrix(); } @@ -47,40 +51,43 @@ if (m_ShadingType != kInvalidShading) return true; - const CPDF_Object* pShadingObj = GetShadingObject(); - const CPDF_Dictionary* pShadingDict = + RetainPtr<const CPDF_Object> pShadingObj = GetShadingObject(); + RetainPtr<const CPDF_Dictionary> pShadingDict = pShadingObj ? pShadingObj->GetDict() : nullptr; if (!pShadingDict) return false; m_pFunctions.clear(); - const CPDF_Object* pFunc = pShadingDict->GetDirectObjectFor("Function"); + RetainPtr<const CPDF_Object> pFunc = + pShadingDict->GetDirectObjectFor("Function"); if (pFunc) { if (const CPDF_Array* pArray = pFunc->AsArray()) { m_pFunctions.resize(std::min<size_t>(pArray->size(), 4)); - for (size_t i = 0; i < m_pFunctions.size(); ++i) + for (size_t i = 0; i < m_pFunctions.size(); ++i) { m_pFunctions[i] = CPDF_Function::Load(pArray->GetDirectObjectAt(i)); + } } else { - m_pFunctions.push_back(CPDF_Function::Load(pFunc)); + m_pFunctions.push_back(CPDF_Function::Load(std::move(pFunc))); } } - const CPDF_Object* pCSObj = pShadingDict->GetDirectObjectFor("ColorSpace"); + RetainPtr<const CPDF_Object> pCSObj = + pShadingDict->GetDirectObjectFor("ColorSpace"); if (!pCSObj) return false; auto* pDocPageData = CPDF_DocPageData::FromDocument(document()); - m_pCS = pDocPageData->GetColorSpace(pCSObj, nullptr); + m_pCS = pDocPageData->GetColorSpace(pCSObj.Get(), nullptr); // The color space is required and cannot be a Pattern space, according to the // PDF 1.7 spec, page 305. - if (!m_pCS || m_pCS->GetFamily() == PDFCS_PATTERN) + if (!m_pCS || m_pCS->GetFamily() == CPDF_ColorSpace::Family::kPattern) return false; m_ShadingType = ToShadingType(pShadingDict->GetIntegerFor("ShadingType")); return Validate(); } -const CPDF_Object* CPDF_ShadingPattern::GetShadingObject() const { +RetainPtr<const CPDF_Object> CPDF_ShadingPattern::GetShadingObject() const { return m_bShading ? pattern_obj() : pattern_obj()->GetDict()->GetDirectObjectFor("Shading"); } @@ -98,7 +105,7 @@ case kFunctionBasedShading: case kAxialShading: case kRadialShading: { - if (m_pCS->GetFamily() == PDFCS_INDEXED) + if (m_pCS->GetFamily() == CPDF_ColorSpace::Family::kIndexed) return false; break; } @@ -106,13 +113,14 @@ case kLatticeFormGouraudTriangleMeshShading: case kCoonsPatchMeshShading: case kTensorProductPatchMeshShading: { - if (!m_pFunctions.empty() && m_pCS->GetFamily() == PDFCS_INDEXED) + if (!m_pFunctions.empty() && + m_pCS->GetFamily() == CPDF_ColorSpace::Family::kIndexed) { return false; + } break; } default: { - NOTREACHED(); - return false; + NOTREACHED_NORETURN(); } } @@ -139,10 +147,8 @@ ValidateFunctions(nNumColorSpaceComponents, 1, 1); } default: - break; + NOTREACHED_NORETURN(); } - NOTREACHED(); - return false; } bool CPDF_ShadingPattern::ValidateFunctions(
diff --git a/core/fpdfapi/page/cpdf_shadingpattern.h b/core/fpdfapi/page/cpdf_shadingpattern.h index 392aa27..1e26720 100644 --- a/core/fpdfapi/page/cpdf_shadingpattern.h +++ b/core/fpdfapi/page/cpdf_shadingpattern.h
@@ -1,4 +1,4 @@ -// Copyright 2016 PDFium Authors. All rights reserved. +// Copyright 2016 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -7,14 +7,14 @@ #ifndef CORE_FPDFAPI_PAGE_CPDF_SHADINGPATTERN_H_ #define CORE_FPDFAPI_PAGE_CPDF_SHADINGPATTERN_H_ +#include <stdint.h> + #include <memory> #include <vector> #include "core/fpdfapi/page/cpdf_colorspace.h" #include "core/fpdfapi/page/cpdf_pattern.h" -#include "core/fxcrt/fx_system.h" #include "core/fxcrt/retain_ptr.h" -#include "core/fxcrt/unowned_ptr.h" // Values used in PDFs except for |kInvalidShading| and |kMaxShading|. // Do not change. @@ -38,9 +38,7 @@ class CPDF_ShadingPattern final : public CPDF_Pattern { public: - template <typename T, typename... Args> - friend RetainPtr<T> pdfium::MakeRetain(Args&&... args); - + CONSTRUCT_VIA_MAKE_RETAIN; ~CPDF_ShadingPattern() override; // CPDF_Pattern: @@ -56,7 +54,7 @@ ShadingType GetShadingType() const { return m_ShadingType; } bool IsShadingObject() const { return m_bShading; } - const CPDF_Object* GetShadingObject() const; + RetainPtr<const CPDF_Object> GetShadingObject() const; RetainPtr<CPDF_ColorSpace> GetCS() const { return m_pCS; } const std::vector<std::unique_ptr<CPDF_Function>>& GetFuncs() const { return m_pFunctions; @@ -64,7 +62,7 @@ private: CPDF_ShadingPattern(CPDF_Document* pDoc, - CPDF_Object* pPatternObj, + RetainPtr<CPDF_Object> pPatternObj, bool bShading, const CFX_Matrix& parentMatrix); CPDF_ShadingPattern(const CPDF_ShadingPattern&) = delete;
diff --git a/core/fpdfapi/page/cpdf_stitchfunc.cpp b/core/fpdfapi/page/cpdf_stitchfunc.cpp index 1ec48ac..f522bc3 100644 --- a/core/fpdfapi/page/cpdf_stitchfunc.cpp +++ b/core/fpdfapi/page/cpdf_stitchfunc.cpp
@@ -1,4 +1,4 @@ -// Copyright 2017 PDFium Authors. All rights reserved. +// Copyright 2017 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -12,6 +12,7 @@ #include "core/fpdfapi/parser/cpdf_dictionary.h" #include "core/fpdfapi/parser/fpdf_parser_utility.h" #include "core/fxcrt/fx_safe_types.h" +#include "core/fxcrt/stl_util.h" namespace { @@ -21,30 +22,29 @@ CPDF_StitchFunc::CPDF_StitchFunc() : CPDF_Function(Type::kType3Stitching) {} -CPDF_StitchFunc::~CPDF_StitchFunc() {} +CPDF_StitchFunc::~CPDF_StitchFunc() = default; -bool CPDF_StitchFunc::v_Init(const CPDF_Object* pObj, - std::set<const CPDF_Object*>* pVisited) { +bool CPDF_StitchFunc::v_Init(const CPDF_Object* pObj, VisitedSet* pVisited) { if (m_nInputs != kRequiredNumInputs) return false; - const CPDF_Dictionary* pDict = pObj->GetDict(); + RetainPtr<const CPDF_Dictionary> pDict = pObj->GetDict(); if (!pDict) return false; - const CPDF_Array* pFunctionsArray = pDict->GetArrayFor("Functions"); + RetainPtr<const CPDF_Array> pFunctionsArray = pDict->GetArrayFor("Functions"); if (!pFunctionsArray) return false; - const CPDF_Array* pBoundsArray = pDict->GetArrayFor("Bounds"); + RetainPtr<const CPDF_Array> pBoundsArray = pDict->GetArrayFor("Bounds"); if (!pBoundsArray) return false; - const CPDF_Array* pEncodeArray = pDict->GetArrayFor("Encode"); + RetainPtr<const CPDF_Array> pEncodeArray = pDict->GetArrayFor("Encode"); if (!pEncodeArray) return false; - const uint32_t nSubs = pFunctionsArray->size(); + const uint32_t nSubs = fxcrt::CollectionSize<uint32_t>(*pFunctionsArray); if (nSubs == 0) return false; @@ -65,13 +65,14 @@ // Check sub-functions. { - Optional<uint32_t> nOutputs; + absl::optional<uint32_t> nOutputs; for (uint32_t i = 0; i < nSubs; ++i) { - const CPDF_Object* pSub = pFunctionsArray->GetDirectObjectAt(i); + RetainPtr<const CPDF_Object> pSub = pFunctionsArray->GetDirectObjectAt(i); if (pSub == pObj) return false; - std::unique_ptr<CPDF_Function> pFunc(CPDF_Function::Load(pSub, pVisited)); + std::unique_ptr<CPDF_Function> pFunc = + CPDF_Function::Load(std::move(pSub), pVisited); if (!pFunc) return false; @@ -84,29 +85,29 @@ if (nFuncOutputs == 0) return false; - if (nOutputs) { - if (nFuncOutputs != *nOutputs) + if (nOutputs.has_value()) { + if (nOutputs != nFuncOutputs) return false; } else { nOutputs = nFuncOutputs; } - m_pSubFunctions.push_back(std::move(pFunc)); } - m_nOutputs = *nOutputs; + m_nOutputs = nOutputs.value(); } m_bounds.reserve(nSubs + 1); m_bounds.push_back(m_Domains[0]); for (uint32_t i = 0; i < nSubs - 1; i++) - m_bounds.push_back(pBoundsArray->GetNumberAt(i)); + m_bounds.push_back(pBoundsArray->GetFloatAt(i)); m_bounds.push_back(m_Domains[1]); - m_encode = ReadArrayElementsToVector(pEncodeArray, nSubs * 2); + m_encode = ReadArrayElementsToVector(pEncodeArray.Get(), nSubs * 2); return true; } -bool CPDF_StitchFunc::v_Call(const float* inputs, float* results) const { +bool CPDF_StitchFunc::v_Call(pdfium::span<const float> inputs, + pdfium::span<float> results) const { float input = inputs[0]; size_t i; for (i = 0; i < m_pSubFunctions.size() - 1; i++) { @@ -115,7 +116,7 @@ } input = Interpolate(input, m_bounds[i], m_bounds[i + 1], m_encode[i * 2], m_encode[i * 2 + 1]); - int nresults; - return m_pSubFunctions[i]->Call(&input, kRequiredNumInputs, results, - &nresults); + return m_pSubFunctions[i] + ->Call(pdfium::make_span(&input, 1), results) + .has_value(); }
diff --git a/core/fpdfapi/page/cpdf_stitchfunc.h b/core/fpdfapi/page/cpdf_stitchfunc.h index 761c9ba..e3490e9 100644 --- a/core/fpdfapi/page/cpdf_stitchfunc.h +++ b/core/fpdfapi/page/cpdf_stitchfunc.h
@@ -1,4 +1,4 @@ -// Copyright 2017 PDFium Authors. All rights reserved. +// Copyright 2017 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -8,7 +8,6 @@ #define CORE_FPDFAPI_PAGE_CPDF_STITCHFUNC_H_ #include <memory> -#include <set> #include <vector> #include "core/fpdfapi/page/cpdf_function.h" @@ -18,10 +17,10 @@ CPDF_StitchFunc(); ~CPDF_StitchFunc() override; - // CPDF_Function - bool v_Init(const CPDF_Object* pObj, - std::set<const CPDF_Object*>* pVisited) override; - bool v_Call(const float* inputs, float* results) const override; + // CPDF_Function: + bool v_Init(const CPDF_Object* pObj, VisitedSet* pVisited) override; + bool v_Call(pdfium::span<const float> inputs, + pdfium::span<float> results) const override; const std::vector<std::unique_ptr<CPDF_Function>>& GetSubFunctions() const { return m_pSubFunctions;
diff --git a/core/fpdfapi/page/cpdf_streamcontentparser.cpp b/core/fpdfapi/page/cpdf_streamcontentparser.cpp index a18bead..0522cf1 100644 --- a/core/fpdfapi/page/cpdf_streamcontentparser.cpp +++ b/core/fpdfapi/page/cpdf_streamcontentparser.cpp
@@ -1,4 +1,4 @@ -// Copyright 2016 PDFium Authors. All rights reserved. +// Copyright 2016 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -34,17 +34,22 @@ #include "core/fpdfapi/parser/cpdf_reference.h" #include "core/fpdfapi/parser/cpdf_stream.h" #include "core/fpdfapi/parser/fpdf_parser_utility.h" +#include "core/fxcrt/autonuller.h" +#include "core/fxcrt/bytestring.h" #include "core/fxcrt/fx_safe_types.h" +#include "core/fxcrt/scoped_set_insertion.h" +#include "core/fxcrt/stl_util.h" +#include "core/fxge/cfx_graphstate.h" #include "core/fxge/cfx_graphstatedata.h" -#include "core/fxge/render_defines.h" -#include "third_party/base/logging.h" -#include "third_party/base/ptr_util.h" +#include "third_party/base/check.h" +#include "third_party/base/containers/contains.h" +#include "third_party/base/no_destructor.h" +#include "third_party/base/notreached.h" #include "third_party/base/span.h" -#include "third_party/base/stl_util.h" namespace { -const int kMaxFormLevel = 30; +const int kMaxFormLevel = 40; const int kSingleCoordinatePair = 1; const int kTensorCoordinatePairs = 16; @@ -60,47 +65,39 @@ const char kPathOperatorClosePath = 'h'; const char kPathOperatorRectangle[] = "re"; -class CPDF_StreamParserAutoClearer { - public: - CPDF_StreamParserAutoClearer(UnownedPtr<CPDF_StreamParser>* scoped_variable, - CPDF_StreamParser* new_parser) - : scoped_variable_(scoped_variable) { - *scoped_variable_ = new_parser; - } - ~CPDF_StreamParserAutoClearer() { *scoped_variable_ = nullptr; } - - private: - UnownedPtr<CPDF_StreamParser>* scoped_variable_; -}; - CFX_FloatRect GetShadingBBox(CPDF_ShadingPattern* pShading, const CFX_Matrix& matrix) { ShadingType type = pShading->GetShadingType(); - const CPDF_Stream* pStream = ToStream(pShading->GetShadingObject()); + RetainPtr<const CPDF_Stream> pStream = ToStream(pShading->GetShadingObject()); RetainPtr<CPDF_ColorSpace> pCS = pShading->GetCS(); if (!pStream || !pCS) return CFX_FloatRect(); - CPDF_MeshStream stream(type, pShading->GetFuncs(), pStream, pCS); + CPDF_MeshStream stream(type, pShading->GetFuncs(), std::move(pStream), + std::move(pCS)); if (!stream.Load()) return CFX_FloatRect(); CFX_FloatRect rect; - bool bStarted = false; + bool update_rect = false; bool bGouraud = type == kFreeFormGouraudTriangleMeshShading || type == kLatticeFormGouraudTriangleMeshShading; - int point_count = kSingleCoordinatePair; + int point_count; if (type == kTensorProductPatchMeshShading) point_count = kTensorCoordinatePairs; else if (type == kCoonsPatchMeshShading) point_count = kCoonsCoordinatePairs; + else + point_count = kSingleCoordinatePair; - int color_count = kSingleColorPerPatch; + int color_count; if (type == kCoonsPatchMeshShading || type == kTensorProductPatchMeshShading) color_count = kQuadColorsPerPatch; + else + color_count = kSingleColorPerPatch; - while (!stream.BitStream()->IsEOF()) { + while (!stream.IsEOF()) { uint32_t flag = 0; if (type != kLatticeFormGouraudTriangleMeshShading) { if (!stream.CanReadFlag()) @@ -113,15 +110,16 @@ color_count -= 2; } - for (int i = 0; i < point_count; i++) { + for (int i = 0; i < point_count; ++i) { if (!stream.CanReadCoords()) break; + CFX_PointF origin = stream.ReadCoords(); - if (bStarted) { + if (update_rect) { rect.UpdateRect(origin); } else { - rect.InitRect(origin); - bStarted = true; + rect = CFX_FloatRect(origin); + update_rect = true; } } FX_SAFE_UINT32 nBits = stream.Components(); @@ -130,9 +128,9 @@ if (!nBits.IsValid()) break; - stream.BitStream()->SkipBits(nBits.ValueOrDie()); + stream.SkipBits(nBits.ValueOrDie()); if (bGouraud) - stream.BitStream()->ByteAlign(); + stream.ByteAlign(); } return matrix.TransformRect(rect); } @@ -163,16 +161,16 @@ ByteStringView replacement; }; -ByteStringView FindFullName(const AbbrPair* table, - size_t count, +ByteStringView FindFullName(pdfium::span<const AbbrPair> table, ByteStringView abbr) { - auto* it = std::find_if(table, table + count, [abbr](const AbbrPair& pair) { - return pair.abbr == abbr; - }); - return it != table + count ? ByteStringView(it->full_name) : ByteStringView(); + for (const auto& pair : table) { + if (pair.abbr == abbr) + return ByteStringView(pair.full_name); + } + return ByteStringView(); } -void ReplaceAbbr(CPDF_Object* pObj); +void ReplaceAbbr(RetainPtr<CPDF_Object> pObj); void ReplaceAbbrInDictionary(CPDF_Dictionary* pDict) { std::vector<AbbrReplacementOp> replacements; @@ -180,9 +178,8 @@ CPDF_DictionaryLocker locker(pDict); for (const auto& it : locker) { ByteString key = it.first; - CPDF_Object* value = it.second.Get(); - ByteStringView fullname = FindFullName( - kInlineKeyAbbr, FX_ArraySize(kInlineKeyAbbr), key.AsStringView()); + ByteStringView fullname = + FindFullName(kInlineKeyAbbr, key.AsStringView()); if (!fullname.IsEmpty()) { AbbrReplacementOp op; op.is_replace_key = true; @@ -191,12 +188,10 @@ replacements.push_back(op); key = fullname; } - + RetainPtr<CPDF_Object> value = it.second; if (value->IsName()) { ByteString name = value->GetString(); - fullname = - FindFullName(kInlineValueAbbr, FX_ArraySize(kInlineValueAbbr), - name.AsStringView()); + fullname = FindFullName(kInlineValueAbbr, name.AsStringView()); if (!fullname.IsEmpty()) { AbbrReplacementOp op; op.is_replace_key = false; @@ -205,7 +200,7 @@ replacements.push_back(op); } } else { - ReplaceAbbr(value); + ReplaceAbbr(std::move(value)); } } } @@ -219,28 +214,27 @@ void ReplaceAbbrInArray(CPDF_Array* pArray) { for (size_t i = 0; i < pArray->size(); ++i) { - CPDF_Object* pElement = pArray->GetObjectAt(i); + RetainPtr<CPDF_Object> pElement = pArray->GetMutableObjectAt(i); if (pElement->IsName()) { ByteString name = pElement->GetString(); ByteStringView fullname = - FindFullName(kInlineValueAbbr, FX_ArraySize(kInlineValueAbbr), - name.AsStringView()); + FindFullName(kInlineValueAbbr, name.AsStringView()); if (!fullname.IsEmpty()) pArray->SetNewAt<CPDF_Name>(i, ByteString(fullname)); } else { - ReplaceAbbr(pElement); + ReplaceAbbr(std::move(pElement)); } } } -void ReplaceAbbr(CPDF_Object* pObj) { - CPDF_Dictionary* pDict = pObj->AsDictionary(); +void ReplaceAbbr(RetainPtr<CPDF_Object> pObj) { + CPDF_Dictionary* pDict = pObj->AsMutableDictionary(); if (pDict) { ReplaceAbbrInDictionary(pDict); return; } - CPDF_Array* pArray = pObj->AsArray(); + CPDF_Array* pArray = pObj->AsMutableArray(); if (pArray) ReplaceAbbrInArray(pArray); } @@ -249,24 +243,24 @@ CPDF_StreamContentParser::CPDF_StreamContentParser( CPDF_Document* pDocument, - CPDF_Dictionary* pPageResources, - CPDF_Dictionary* pParentResources, + RetainPtr<CPDF_Dictionary> pPageResources, + RetainPtr<CPDF_Dictionary> pParentResources, const CFX_Matrix* pmtContentToUser, CPDF_PageObjectHolder* pObjHolder, - CPDF_Dictionary* pResources, + RetainPtr<CPDF_Dictionary> pResources, const CFX_FloatRect& rcBBox, const CPDF_AllStates* pStates, std::set<const uint8_t*>* pParsedSet) : m_pDocument(pDocument), m_pPageResources(pPageResources), m_pParentResources(pParentResources), - m_pResources(CPDF_Form::ChooseResourcesDict(pResources, - pParentResources, - pPageResources)), + m_pResources(CPDF_Form::ChooseResourcesDict(pResources.Get(), + pParentResources.Get(), + pPageResources.Get())), m_pObjectHolder(pObjHolder), m_ParsedSet(pParsedSet), m_BBox(rcBBox), - m_pCurStates(pdfium::MakeUnique<CPDF_AllStates>()) { + m_pCurStates(std::make_unique<CPDF_AllStates>()) { if (pmtContentToUser) m_mtContentToUser = *pmtContentToUser; if (pStates) { @@ -279,7 +273,7 @@ } // Add the sentinel. - m_ContentMarksStack.push(pdfium::MakeUnique<CPDF_ContentMarks>()); + m_ContentMarksStack.push(std::make_unique<CPDF_ContentMarks>()); } CPDF_StreamContentParser::~CPDF_StreamContentParser() { @@ -292,7 +286,7 @@ if (m_ParamStartPos == kParamBufSize) { m_ParamStartPos = 0; } - if (m_ParamBuf[m_ParamStartPos].m_Type == ContentParam::OBJECT) + if (m_ParamBuf[m_ParamStartPos].m_Type == ContentParam::Type::kObject) m_ParamBuf[m_ParamStartPos].m_pObject.Reset(); return m_ParamStartPos; @@ -307,27 +301,26 @@ void CPDF_StreamContentParser::AddNameParam(ByteStringView bsName) { ContentParam& param = m_ParamBuf[GetNextParamPos()]; - param.m_Type = ContentParam::NAME; - param.m_Name = - bsName.Contains('#') ? PDF_NameDecode(bsName) : ByteString(bsName); + param.m_Type = ContentParam::Type::kName; + param.m_Name = PDF_NameDecode(bsName); } void CPDF_StreamContentParser::AddNumberParam(ByteStringView str) { ContentParam& param = m_ParamBuf[GetNextParamPos()]; - param.m_Type = ContentParam::NUMBER; + param.m_Type = ContentParam::Type::kNumber; param.m_Number = FX_Number(str); } void CPDF_StreamContentParser::AddObjectParam(RetainPtr<CPDF_Object> pObj) { ContentParam& param = m_ParamBuf[GetNextParamPos()]; - param.m_Type = ContentParam::OBJECT; + param.m_Type = ContentParam::Type::kObject; param.m_pObject = std::move(pObj); } void CPDF_StreamContentParser::ClearAllParams() { uint32_t index = m_ParamStartPos; for (uint32_t i = 0; i < m_ParamCount; i++) { - if (m_ParamBuf[index].m_Type == ContentParam::OBJECT) + if (m_ParamBuf[index].m_Type == ContentParam::Type::kObject) m_ParamBuf[index].m_pObject.Reset(); index++; if (index == kParamBufSize) @@ -337,7 +330,7 @@ m_ParamCount = 0; } -CPDF_Object* CPDF_StreamContentParser::GetObject(uint32_t index) { +RetainPtr<CPDF_Object> CPDF_StreamContentParser::GetObject(uint32_t index) { if (index >= m_ParamCount) { return nullptr; } @@ -346,24 +339,23 @@ real_index -= kParamBufSize; } ContentParam& param = m_ParamBuf[real_index]; - if (param.m_Type == ContentParam::NUMBER) { - param.m_Type = ContentParam::OBJECT; + if (param.m_Type == ContentParam::Type::kNumber) { + param.m_Type = ContentParam::Type::kObject; param.m_pObject = param.m_Number.IsInteger() ? pdfium::MakeRetain<CPDF_Number>(param.m_Number.GetSigned()) : pdfium::MakeRetain<CPDF_Number>(param.m_Number.GetFloat()); - return param.m_pObject.Get(); + return param.m_pObject; } - if (param.m_Type == ContentParam::NAME) { - param.m_Type = ContentParam::OBJECT; + if (param.m_Type == ContentParam::Type::kName) { + param.m_Type = ContentParam::Type::kObject; param.m_pObject = m_pDocument->New<CPDF_Name>(param.m_Name); - return param.m_pObject.Get(); + return param.m_pObject; } - if (param.m_Type == ContentParam::OBJECT) - return param.m_pObject.Get(); + if (param.m_Type == ContentParam::Type::kObject) + return param.m_pObject; - NOTREACHED(); - return nullptr; + NOTREACHED_NORETURN(); } ByteString CPDF_StreamContentParser::GetString(uint32_t index) const { @@ -375,10 +367,10 @@ real_index -= kParamBufSize; const ContentParam& param = m_ParamBuf[real_index]; - if (param.m_Type == ContentParam::NAME) + if (param.m_Type == ContentParam::Type::kName) return param.m_Name; - if (param.m_Type == 0 && param.m_pObject) + if (param.m_Type == ContentParam::Type::kObject && param.m_pObject) return param.m_pObject->GetString(); return ByteString(); @@ -393,10 +385,10 @@ real_index -= kParamBufSize; const ContentParam& param = m_ParamBuf[real_index]; - if (param.m_Type == ContentParam::NUMBER) + if (param.m_Type == ContentParam::Type::kNumber) return param.m_Number.GetFloat(); - if (param.m_Type == 0 && param.m_pObject) + if (param.m_Type == ContentParam::Type::kObject && param.m_pObject) return param.m_pObject->GetNumber(); return 0; @@ -409,13 +401,22 @@ return values; } +CFX_PointF CPDF_StreamContentParser::GetPoint(uint32_t index) const { + return CFX_PointF(GetNumber(index + 1), GetNumber(index)); +} + +CFX_Matrix CPDF_StreamContentParser::GetMatrix() const { + return CFX_Matrix(GetNumber(5), GetNumber(4), GetNumber(3), GetNumber(2), + GetNumber(1), GetNumber(0)); +} + void CPDF_StreamContentParser::SetGraphicStates(CPDF_PageObject* pObj, bool bColor, bool bText, bool bGraph) { pObj->m_GeneralState = m_pCurStates->m_GeneralState; pObj->m_ClipPath = m_pCurStates->m_ClipPath; - pObj->m_ContentMarks = *m_ContentMarksStack.top(); + pObj->SetContentMarks(*m_ContentMarksStack.top()); if (bColor) { pObj->m_ColorState = m_pCurStates->m_ColorState; } @@ -425,6 +426,7 @@ if (bText) { pObj->m_TextState = m_pCurStates->m_TextState; } + pObj->SetGraphicsResourceName(m_pCurStates->m_GraphicsResourceName); } // static @@ -549,33 +551,34 @@ } void CPDF_StreamContentParser::OnOperator(ByteStringView op) { - static const OpCodes s_OpCodes = InitializeOpCodes(); + static const pdfium::base::NoDestructor<OpCodes> s_OpCodes( + InitializeOpCodes()); - auto it = s_OpCodes.find(op.GetID()); - if (it != s_OpCodes.end()) + auto it = s_OpCodes->find(op.GetID()); + if (it != s_OpCodes->end()) (this->*it->second)(); } void CPDF_StreamContentParser::Handle_CloseFillStrokePath() { Handle_ClosePath(); - AddPathObject(FXFILL_WINDING, true); + AddPathObject(CFX_FillRenderOptions::FillType::kWinding, RenderType::kStroke); } void CPDF_StreamContentParser::Handle_FillStrokePath() { - AddPathObject(FXFILL_WINDING, true); + AddPathObject(CFX_FillRenderOptions::FillType::kWinding, RenderType::kStroke); } void CPDF_StreamContentParser::Handle_CloseEOFillStrokePath() { - AddPathPoint(m_PathStartX, m_PathStartY, FXPT_TYPE::LineTo, true); - AddPathObject(FXFILL_ALTERNATE, true); + AddPathPointAndClose(m_PathStart, CFX_Path::Point::Type::kLine); + AddPathObject(CFX_FillRenderOptions::FillType::kEvenOdd, RenderType::kStroke); } void CPDF_StreamContentParser::Handle_EOFillStrokePath() { - AddPathObject(FXFILL_ALTERNATE, true); + AddPathObject(CFX_FillRenderOptions::FillType::kEvenOdd, RenderType::kStroke); } void CPDF_StreamContentParser::Handle_BeginMarkedContent_Dictionary() { - CPDF_Object* pProperty = GetObject(0); + RetainPtr<CPDF_Object> pProperty = GetObject(0); if (!pProperty) return; @@ -585,12 +588,13 @@ if (pProperty->IsName()) { ByteString property_name = pProperty->GetString(); - CPDF_Dictionary* pHolder = FindResourceHolder("Properties"); + RetainPtr<CPDF_Dictionary> pHolder = FindResourceHolder("Properties"); if (!pHolder || !pHolder->GetDictFor(property_name)) return; - new_marks->AddMarkWithPropertiesHolder(tag, pHolder, property_name); + new_marks->AddMarkWithPropertiesHolder(tag, std::move(pHolder), + property_name); } else if (pProperty->IsDictionary()) { - new_marks->AddMarkWithDirectDict(tag, pProperty->AsDictionary()); + new_marks->AddMarkWithDirectDict(tag, ToDictionary(pProperty)); } else { return; } @@ -600,31 +604,28 @@ void CPDF_StreamContentParser::Handle_BeginImage() { FX_FILESIZE savePos = m_pSyntax->GetPos(); auto pDict = m_pDocument->New<CPDF_Dictionary>(); - while (1) { - CPDF_StreamParser::SyntaxType type = m_pSyntax->ParseNextElement(); - if (type == CPDF_StreamParser::Keyword) { + while (true) { + CPDF_StreamParser::ElementType type = m_pSyntax->ParseNextElement(); + if (type == CPDF_StreamParser::ElementType::kKeyword) { if (m_pSyntax->GetWord() != "ID") { m_pSyntax->SetPos(savePos); return; } } - if (type != CPDF_StreamParser::Name) { + if (type != CPDF_StreamParser::ElementType::kName) { break; } auto word = m_pSyntax->GetWord(); ByteString key(word.Last(word.GetLength() - 1)); auto pObj = m_pSyntax->ReadNextObject(false, false, 0); - if (!key.IsEmpty()) { - if (pObj && !pObj->IsInline()) { - pDict->SetNewFor<CPDF_Reference>(key, m_pDocument.Get(), - pObj->GetObjNum()); - } else { - pDict->SetFor(key, std::move(pObj)); - } + if (pObj && !pObj->IsInline()) { + pDict->SetNewFor<CPDF_Reference>(key, m_pDocument, pObj->GetObjNum()); + } else { + pDict->SetFor(key, std::move(pObj)); } } - ReplaceAbbr(pDict.Get()); - CPDF_Object* pCSObj = nullptr; + ReplaceAbbr(pDict); + RetainPtr<const CPDF_Object> pCSObj; if (pDict->KeyExist("ColorSpace")) { pCSObj = pDict->GetDirectObjectFor("ColorSpace"); if (pCSObj->IsName()) { @@ -638,20 +639,20 @@ } pDict->SetNewFor<CPDF_Name>("Subtype", "Image"); RetainPtr<CPDF_Stream> pStream = - m_pSyntax->ReadInlineStream(m_pDocument.Get(), std::move(pDict), pCSObj); - while (1) { - CPDF_StreamParser::SyntaxType type = m_pSyntax->ParseNextElement(); - if (type == CPDF_StreamParser::EndOfData) { + m_pSyntax->ReadInlineStream(m_pDocument, std::move(pDict), pCSObj.Get()); + while (true) { + CPDF_StreamParser::ElementType type = m_pSyntax->ParseNextElement(); + if (type == CPDF_StreamParser::ElementType::kEndOfData) break; - } - if (type != CPDF_StreamParser::Keyword) { + + if (type != CPDF_StreamParser::ElementType::kKeyword) continue; - } - if (m_pSyntax->GetWord() == "EI") { + + if (m_pSyntax->GetWord() == "EI") break; - } } - CPDF_ImageObject* pObj = AddImage(std::move(pStream)); + CPDF_ImageObject* pObj = + AddImageFromStream(std::move(pStream), /*resource_name=*/""); // Record the bounding box of this image, so rendering code can draw it // properly. if (pObj && pObj->GetImage()->IsMask()) @@ -673,15 +674,13 @@ } void CPDF_StreamContentParser::Handle_CurveTo_123() { - AddPathPoint(GetNumber(5), GetNumber(4), FXPT_TYPE::BezierTo, false); - AddPathPoint(GetNumber(3), GetNumber(2), FXPT_TYPE::BezierTo, false); - AddPathPoint(GetNumber(1), GetNumber(0), FXPT_TYPE::BezierTo, false); + AddPathPoint(GetPoint(4), CFX_Path::Point::Type::kBezier); + AddPathPoint(GetPoint(2), CFX_Path::Point::Type::kBezier); + AddPathPoint(GetPoint(0), CFX_Path::Point::Type::kBezier); } void CPDF_StreamContentParser::Handle_ConcatMatrix() { - CFX_Matrix new_matrix(GetNumber(5), GetNumber(4), GetNumber(3), GetNumber(2), - GetNumber(1), GetNumber(0)); - m_pCurStates->m_CTM = new_matrix * m_pCurStates->m_CTM; + m_pCurStates->m_CTM = GetMatrix() * m_pCurStates->m_CTM; OnChangeTextMatrix(); } @@ -690,7 +689,8 @@ if (!pCS) return; - m_pCurStates->m_ColorState.GetMutableFillColor()->SetColorSpace(pCS); + m_pCurStates->m_ColorState.GetMutableFillColor()->SetColorSpace( + std::move(pCS)); } void CPDF_StreamContentParser::Handle_SetColorSpace_Stroke() { @@ -698,15 +698,16 @@ if (!pCS) return; - m_pCurStates->m_ColorState.GetMutableStrokeColor()->SetColorSpace(pCS); + m_pCurStates->m_ColorState.GetMutableStrokeColor()->SetColorSpace( + std::move(pCS)); } void CPDF_StreamContentParser::Handle_SetDash() { - CPDF_Array* pArray = ToArray(GetObject(1)); + RetainPtr<CPDF_Array> pArray = ToArray(GetObject(1)); if (!pArray) return; - m_pCurStates->SetLineDash(pArray, GetNumber(0), 1.0f); + m_pCurStates->SetLineDash(pArray.Get(), GetNumber(0), 1.0f); } void CPDF_StreamContentParser::Handle_SetCharWidth() { @@ -726,7 +727,7 @@ ByteString name = GetString(0); if (name == m_LastImageName && m_pLastImage && m_pLastImage->GetStream() && m_pLastImage->GetStream()->GetObjNum()) { - CPDF_ImageObject* pObj = AddImage(m_pLastImage); + CPDF_ImageObject* pObj = AddLastImage(); // Record the bounding box of this image, so rendering code can draw it // properly. if (pObj && pObj->GetImage()->IsMask()) @@ -734,25 +735,24 @@ return; } - CPDF_Stream* pXObject = ToStream(FindResourceObj("XObject", name)); - if (!pXObject) { - m_bResourceMissing = true; + RetainPtr<CPDF_Stream> pXObject(ToStream(FindResourceObj("XObject", name))); + if (!pXObject) return; - } ByteString type; if (pXObject->GetDict()) - type = pXObject->GetDict()->GetStringFor("Subtype"); + type = pXObject->GetDict()->GetByteStringFor("Subtype"); if (type == "Form") { - AddForm(pXObject); + AddForm(std::move(pXObject), name); return; } if (type == "Image") { - CPDF_ImageObject* pObj = pXObject->IsInline() - ? AddImage(ToStream(pXObject->Clone())) - : AddImage(pXObject->GetObjNum()); + CPDF_ImageObject* pObj = + pXObject->IsInline() + ? AddImageFromStream(ToStream(pXObject->Clone()), name) + : AddImageFromStreamObjNum(pXObject->GetObjNum(), name); m_LastImageName = std::move(name); if (pObj) { @@ -763,20 +763,22 @@ } } -void CPDF_StreamContentParser::AddForm(CPDF_Stream* pStream) { +void CPDF_StreamContentParser::AddForm(RetainPtr<CPDF_Stream> pStream, + const ByteString& name) { CPDF_AllStates status; status.m_GeneralState = m_pCurStates->m_GeneralState; status.m_GraphState = m_pCurStates->m_GraphState; status.m_ColorState = m_pCurStates->m_ColorState; status.m_TextState = m_pCurStates->m_TextState; - auto form = pdfium::MakeUnique<CPDF_Form>( - m_pDocument.Get(), m_pPageResources.Get(), pStream, m_pResources.Get()); - form->ParseContent(&status, nullptr, m_ParsedSet.Get()); + auto form = std::make_unique<CPDF_Form>( + m_pDocument, m_pPageResources, std::move(pStream), m_pResources.Get()); + form->ParseContent(&status, nullptr, m_ParsedSet); CFX_Matrix matrix = m_pCurStates->m_CTM * m_mtContentToUser; - - auto pFormObj = pdfium::MakeUnique<CPDF_FormObject>(GetCurrentStreamIndex(), - std::move(form), matrix); + auto pFormObj = std::make_unique<CPDF_FormObject>(GetCurrentStreamIndex(), + std::move(form), matrix); + pFormObj->SetResourceName(name); + pFormObj->SetGraphicsResourceName(m_pCurStates->m_GraphicsResourceName); if (!m_pObjectHolder->BackgroundAlphaNeeded() && pFormObj->form()->BackgroundAlphaNeeded()) { m_pObjectHolder->SetBackgroundAlphaNeeded(true); @@ -786,37 +788,38 @@ m_pObjectHolder->AppendPageObject(std::move(pFormObj)); } -CPDF_ImageObject* CPDF_StreamContentParser::AddImage( - RetainPtr<CPDF_Stream> pStream) { +CPDF_ImageObject* CPDF_StreamContentParser::AddImageFromStream( + RetainPtr<CPDF_Stream> pStream, + const ByteString& name) { if (!pStream) return nullptr; - auto pImageObj = - pdfium::MakeUnique<CPDF_ImageObject>(GetCurrentStreamIndex()); + auto pImageObj = std::make_unique<CPDF_ImageObject>(GetCurrentStreamIndex()); + pImageObj->SetResourceName(name); pImageObj->SetImage( - pdfium::MakeRetain<CPDF_Image>(m_pDocument.Get(), std::move(pStream))); + pdfium::MakeRetain<CPDF_Image>(m_pDocument, std::move(pStream))); return AddImageObject(std::move(pImageObj)); } -CPDF_ImageObject* CPDF_StreamContentParser::AddImage(uint32_t streamObjNum) { - auto pImageObj = - pdfium::MakeUnique<CPDF_ImageObject>(GetCurrentStreamIndex()); - pImageObj->SetImage(CPDF_DocPageData::FromDocument(m_pDocument.Get()) - ->GetImage(streamObjNum)); +CPDF_ImageObject* CPDF_StreamContentParser::AddImageFromStreamObjNum( + uint32_t stream_obj_num, + const ByteString& name) { + auto pImageObj = std::make_unique<CPDF_ImageObject>(GetCurrentStreamIndex()); + pImageObj->SetResourceName(name); + pImageObj->SetImage( + CPDF_DocPageData::FromDocument(m_pDocument)->GetImage(stream_obj_num)); return AddImageObject(std::move(pImageObj)); } -CPDF_ImageObject* CPDF_StreamContentParser::AddImage( - const RetainPtr<CPDF_Image>& pImage) { - if (!pImage) - return nullptr; +CPDF_ImageObject* CPDF_StreamContentParser::AddLastImage() { + DCHECK(m_pLastImage); - auto pImageObj = - pdfium::MakeUnique<CPDF_ImageObject>(GetCurrentStreamIndex()); - pImageObj->SetImage(CPDF_DocPageData::FromDocument(m_pDocument.Get()) - ->GetImage(pImage->GetStream()->GetObjNum())); + auto pImageObj = std::make_unique<CPDF_ImageObject>(GetCurrentStreamIndex()); + pImageObj->SetResourceName(m_LastImageName); + pImageObj->SetImage(CPDF_DocPageData::FromDocument(m_pDocument) + ->GetImage(m_pLastImage->GetStream()->GetObjNum())); return AddImageObject(std::move(pImageObj)); } @@ -827,8 +830,7 @@ false); CFX_Matrix ImageMatrix = m_pCurStates->m_CTM * m_mtContentToUser; - pImageObj->set_matrix(ImageMatrix); - pImageObj->CalcBoundingBox(); + pImageObj->SetImageMatrix(ImageMatrix); CPDF_ImageObject* pRet = pImageObj.get(); m_pObjectHolder->AppendPageObject(std::move(pImageObj)); @@ -836,12 +838,12 @@ } std::vector<float> CPDF_StreamContentParser::GetColors() const { - ASSERT(m_ParamCount > 0); + DCHECK(m_ParamCount > 0); return GetNumbers(m_ParamCount); } std::vector<float> CPDF_StreamContentParser::GetNamedColors() const { - ASSERT(m_ParamCount > 0); + DCHECK(m_ParamCount > 0); const uint32_t nvalues = m_ParamCount - 1; std::vector<float> values(nvalues); for (size_t i = 0; i < nvalues; ++i) @@ -871,47 +873,49 @@ } void CPDF_StreamContentParser::Handle_FillPath() { - AddPathObject(FXFILL_WINDING, false); + AddPathObject(CFX_FillRenderOptions::FillType::kWinding, RenderType::kFill); } void CPDF_StreamContentParser::Handle_FillPathOld() { - AddPathObject(FXFILL_WINDING, false); + AddPathObject(CFX_FillRenderOptions::FillType::kWinding, RenderType::kFill); } void CPDF_StreamContentParser::Handle_EOFillPath() { - AddPathObject(FXFILL_ALTERNATE, false); + AddPathObject(CFX_FillRenderOptions::FillType::kEvenOdd, RenderType::kFill); } void CPDF_StreamContentParser::Handle_SetGray_Fill() { - RetainPtr<CPDF_ColorSpace> pCS = - CPDF_ColorSpace::GetStockCS(PDFCS_DEVICEGRAY); - m_pCurStates->m_ColorState.SetFillColor(pCS, GetNumbers(1)); + m_pCurStates->m_ColorState.SetFillColor( + CPDF_ColorSpace::GetStockCS(CPDF_ColorSpace::Family::kDeviceGray), + GetNumbers(1)); } void CPDF_StreamContentParser::Handle_SetGray_Stroke() { - RetainPtr<CPDF_ColorSpace> pCS = - CPDF_ColorSpace::GetStockCS(PDFCS_DEVICEGRAY); - m_pCurStates->m_ColorState.SetStrokeColor(pCS, GetNumbers(1)); + m_pCurStates->m_ColorState.SetStrokeColor( + CPDF_ColorSpace::GetStockCS(CPDF_ColorSpace::Family::kDeviceGray), + GetNumbers(1)); } void CPDF_StreamContentParser::Handle_SetExtendGraphState() { ByteString name = GetString(0); - CPDF_Dictionary* pGS = ToDictionary(FindResourceObj("ExtGState", name)); - if (!pGS) { - m_bResourceMissing = true; + RetainPtr<CPDF_Dictionary> pGS = + ToDictionary(FindResourceObj("ExtGState", name)); + if (!pGS) return; - } - m_pCurStates->ProcessExtGS(pGS, this); + + m_pCurStates->m_GraphicsResourceName = name; + m_pCurStates->ProcessExtGS(pGS.Get(), this); } void CPDF_StreamContentParser::Handle_ClosePath() { if (m_PathPoints.empty()) return; - if (m_PathStartX != m_PathCurrentX || m_PathStartY != m_PathCurrentY) - AddPathPoint(m_PathStartX, m_PathStartY, FXPT_TYPE::LineTo, true); - else if (m_PathPoints.back().m_Type != FXPT_TYPE::MoveTo) + if (m_PathStart.x != m_PathCurrent.x || m_PathStart.y != m_PathCurrent.y) { + AddPathPointAndClose(m_PathStart, CFX_Path::Point::Type::kLine); + } else { m_PathPoints.back().m_CloseFigure = true; + } } void CPDF_StreamContentParser::Handle_SetFlat() { @@ -934,32 +938,32 @@ if (m_ParamCount != 4) return; - RetainPtr<CPDF_ColorSpace> pCS = - CPDF_ColorSpace::GetStockCS(PDFCS_DEVICECMYK); - m_pCurStates->m_ColorState.SetFillColor(pCS, GetNumbers(4)); + m_pCurStates->m_ColorState.SetFillColor( + CPDF_ColorSpace::GetStockCS(CPDF_ColorSpace::Family::kDeviceCMYK), + GetNumbers(4)); } void CPDF_StreamContentParser::Handle_SetCMYKColor_Stroke() { if (m_ParamCount != 4) return; - RetainPtr<CPDF_ColorSpace> pCS = - CPDF_ColorSpace::GetStockCS(PDFCS_DEVICECMYK); - m_pCurStates->m_ColorState.SetStrokeColor(pCS, GetNumbers(4)); + m_pCurStates->m_ColorState.SetStrokeColor( + CPDF_ColorSpace::GetStockCS(CPDF_ColorSpace::Family::kDeviceCMYK), + GetNumbers(4)); } void CPDF_StreamContentParser::Handle_LineTo() { if (m_ParamCount != 2) return; - AddPathPoint(GetNumber(1), GetNumber(0), FXPT_TYPE::LineTo, false); + AddPathPoint(GetPoint(0), CFX_Path::Point::Type::kLine); } void CPDF_StreamContentParser::Handle_MoveTo() { if (m_ParamCount != 2) return; - AddPathPoint(GetNumber(1), GetNumber(0), FXPT_TYPE::MoveTo, false); + AddPathPoint(GetPoint(0), CFX_Path::Point::Type::kMove); ParsePathObject(); } @@ -970,11 +974,11 @@ void CPDF_StreamContentParser::Handle_MarkPlace() {} void CPDF_StreamContentParser::Handle_EndPath() { - AddPathObject(0, false); + AddPathObject(CFX_FillRenderOptions::FillType::kNoFill, RenderType::kFill); } void CPDF_StreamContentParser::Handle_SaveGraphState() { - auto pStates = pdfium::MakeUnique<CPDF_AllStates>(); + auto pStates = std::make_unique<CPDF_AllStates>(); pStates->Copy(*m_pCurStates); m_StateStack.push_back(std::move(pStates)); } @@ -988,44 +992,48 @@ } void CPDF_StreamContentParser::Handle_Rectangle() { - float x = GetNumber(3), y = GetNumber(2); - float w = GetNumber(1), h = GetNumber(0); + float x = GetNumber(3); + float y = GetNumber(2); + float w = GetNumber(1); + float h = GetNumber(0); AddPathRect(x, y, w, h); } void CPDF_StreamContentParser::AddPathRect(float x, float y, float w, float h) { - AddPathPoint(x, y, FXPT_TYPE::MoveTo, false); - AddPathPoint(x + w, y, FXPT_TYPE::LineTo, false); - AddPathPoint(x + w, y + h, FXPT_TYPE::LineTo, false); - AddPathPoint(x, y + h, FXPT_TYPE::LineTo, false); - AddPathPoint(x, y, FXPT_TYPE::LineTo, true); + AddPathPoint({x, y}, CFX_Path::Point::Type::kMove); + AddPathPoint({x + w, y}, CFX_Path::Point::Type::kLine); + AddPathPoint({x + w, y + h}, CFX_Path::Point::Type::kLine); + AddPathPoint({x, y + h}, CFX_Path::Point::Type::kLine); + AddPathPointAndClose({x, y}, CFX_Path::Point::Type::kLine); } void CPDF_StreamContentParser::Handle_SetRGBColor_Fill() { if (m_ParamCount != 3) return; - RetainPtr<CPDF_ColorSpace> pCS = CPDF_ColorSpace::GetStockCS(PDFCS_DEVICERGB); - m_pCurStates->m_ColorState.SetFillColor(pCS, GetNumbers(3)); + m_pCurStates->m_ColorState.SetFillColor( + CPDF_ColorSpace::GetStockCS(CPDF_ColorSpace::Family::kDeviceRGB), + GetNumbers(3)); } void CPDF_StreamContentParser::Handle_SetRGBColor_Stroke() { if (m_ParamCount != 3) return; - RetainPtr<CPDF_ColorSpace> pCS = CPDF_ColorSpace::GetStockCS(PDFCS_DEVICERGB); - m_pCurStates->m_ColorState.SetStrokeColor(pCS, GetNumbers(3)); + m_pCurStates->m_ColorState.SetStrokeColor( + CPDF_ColorSpace::GetStockCS(CPDF_ColorSpace::Family::kDeviceRGB), + GetNumbers(3)); } void CPDF_StreamContentParser::Handle_SetRenderIntent() {} void CPDF_StreamContentParser::Handle_CloseStrokePath() { Handle_ClosePath(); - AddPathObject(0, true); + AddPathObject(CFX_FillRenderOptions::FillType::kNoFill, RenderType::kStroke); } void CPDF_StreamContentParser::Handle_StrokePath() { - AddPathObject(0, true); + AddPathObject(CFX_FillRenderOptions::FillType::kNoFill, RenderType::kStroke); } void CPDF_StreamContentParser::Handle_SetColor_Fill() { @@ -1039,7 +1047,7 @@ } void CPDF_StreamContentParser::Handle_SetColorPS_Fill() { - CPDF_Object* pLastParam = GetObject(0); + RetainPtr<CPDF_Object> pLastParam = GetObject(0); if (!pLastParam) return; @@ -1050,13 +1058,16 @@ // A valid |pLastParam| implies |m_ParamCount| > 0, so GetNamedColors() call // below is safe. - RetainPtr<CPDF_Pattern> pPattern = FindPattern(GetString(0), false); - if (pPattern) - m_pCurStates->m_ColorState.SetFillPattern(pPattern, GetNamedColors()); + RetainPtr<CPDF_Pattern> pPattern = FindPattern(GetString(0)); + if (!pPattern) + return; + + std::vector<float> values = GetNamedColors(); + m_pCurStates->m_ColorState.SetFillPattern(std::move(pPattern), values); } void CPDF_StreamContentParser::Handle_SetColorPS_Stroke() { - CPDF_Object* pLastParam = GetObject(0); + RetainPtr<CPDF_Object> pLastParam = GetObject(0); if (!pLastParam) return; @@ -1067,17 +1078,16 @@ // A valid |pLastParam| implies |m_ParamCount| > 0, so GetNamedColors() call // below is safe. - RetainPtr<CPDF_Pattern> pPattern = FindPattern(GetString(0), false); - if (pPattern) - m_pCurStates->m_ColorState.SetStrokePattern(pPattern, GetNamedColors()); -} - -void CPDF_StreamContentParser::Handle_ShadeFill() { - RetainPtr<CPDF_Pattern> pPattern = FindPattern(GetString(0), true); + RetainPtr<CPDF_Pattern> pPattern = FindPattern(GetString(0)); if (!pPattern) return; - CPDF_ShadingPattern* pShading = pPattern->AsShadingPattern(); + std::vector<float> values = GetNamedColors(); + m_pCurStates->m_ColorState.SetStrokePattern(std::move(pPattern), values); +} + +void CPDF_StreamContentParser::Handle_ShadeFill() { + RetainPtr<CPDF_ShadingPattern> pShading = FindShading(GetString(0)); if (!pShading) return; @@ -1085,13 +1095,13 @@ return; CFX_Matrix matrix = m_pCurStates->m_CTM * m_mtContentToUser; - auto pObj = pdfium::MakeUnique<CPDF_ShadingObject>(GetCurrentStreamIndex(), - pShading, matrix); + auto pObj = std::make_unique<CPDF_ShadingObject>(GetCurrentStreamIndex(), + pShading, matrix); SetGraphicStates(pObj.get(), false, false, false); CFX_FloatRect bbox = pObj->m_ClipPath.HasRef() ? pObj->m_ClipPath.GetClipBox() : m_BBox; if (pShading->IsMeshShading()) - bbox.Intersect(GetShadingBBox(pShading, pObj->matrix())); + bbox.Intersect(GetShadingBBox(pShading.Get(), pObj->matrix())); pObj->SetRect(bbox); m_pObjectHolder->AppendPageObject(std::move(pObj)); } @@ -1101,7 +1111,7 @@ } void CPDF_StreamContentParser::Handle_MoveTextPoint() { - m_pCurStates->m_TextLinePos += CFX_PointF(GetNumber(1), GetNumber(0)); + m_pCurStates->m_TextLinePos += GetPoint(0); m_pCurStates->m_TextPos = m_pCurStates->m_TextLinePos; } @@ -1111,52 +1121,51 @@ } void CPDF_StreamContentParser::Handle_SetFont() { - float fs = GetNumber(0); - if (fs == 0) { - constexpr float kDefaultFontSize = 0.0f; - fs = kDefaultFontSize; - } - - m_pCurStates->m_TextState.SetFontSize(fs); + m_pCurStates->m_TextState.SetFontSize(GetNumber(0)); RetainPtr<CPDF_Font> pFont = FindFont(GetString(1)); if (pFont) - m_pCurStates->m_TextState.SetFont(pFont); + m_pCurStates->m_TextState.SetFont(std::move(pFont)); } -CPDF_Dictionary* CPDF_StreamContentParser::FindResourceHolder( +RetainPtr<CPDF_Dictionary> CPDF_StreamContentParser::FindResourceHolder( const ByteString& type) { if (!m_pResources) return nullptr; - CPDF_Dictionary* pDict = m_pResources->GetDictFor(type); + RetainPtr<CPDF_Dictionary> pDict = m_pResources->GetMutableDictFor(type); if (pDict) return pDict; if (m_pResources == m_pPageResources || !m_pPageResources) return nullptr; - return m_pPageResources->GetDictFor(type); + return m_pPageResources->GetMutableDictFor(type); } -CPDF_Object* CPDF_StreamContentParser::FindResourceObj(const ByteString& type, - const ByteString& name) { - CPDF_Dictionary* pHolder = FindResourceHolder(type); - return pHolder ? pHolder->GetDirectObjectFor(name) : nullptr; +RetainPtr<CPDF_Object> CPDF_StreamContentParser::FindResourceObj( + const ByteString& type, + const ByteString& name) { + RetainPtr<CPDF_Dictionary> pHolder = FindResourceHolder(type); + return pHolder ? pHolder->GetMutableDirectObjectFor(name) : nullptr; } RetainPtr<CPDF_Font> CPDF_StreamContentParser::FindFont( const ByteString& name) { - CPDF_Dictionary* pFontDict = ToDictionary(FindResourceObj("Font", name)); + RetainPtr<CPDF_Dictionary> pFontDict( + ToDictionary(FindResourceObj("Font", name))); if (!pFontDict) { - m_bResourceMissing = true; - return CPDF_Font::GetStockFont(m_pDocument.Get(), - CFX_Font::kDefaultAnsiFontName); + return CPDF_Font::GetStockFont(m_pDocument, CFX_Font::kDefaultAnsiFontName); } - RetainPtr<CPDF_Font> pFont = - CPDF_DocPageData::FromDocument(m_pDocument.Get())->GetFont(pFontDict); - if (pFont && pFont->IsType3Font()) { - pFont->AsType3Font()->SetPageResources(m_pResources.Get()); - pFont->AsType3Font()->CheckType3FontMetrics(); + RetainPtr<CPDF_Font> pFont = CPDF_DocPageData::FromDocument(m_pDocument) + ->GetFont(std::move(pFontDict)); + if (pFont) { + // Save `name` for later retrieval by the CPDF_TextObject that uses the + // font. + pFont->SetResourceName(name); + if (pFont->IsType3Font()) { + pFont->AsType3Font()->SetPageResources(m_pResources.Get()); + pFont->AsType3Font()->CheckType3FontMetrics(); + } } return pFont; } @@ -1164,44 +1173,49 @@ RetainPtr<CPDF_ColorSpace> CPDF_StreamContentParser::FindColorSpace( const ByteString& name) { if (name == "Pattern") - return CPDF_ColorSpace::GetStockCS(PDFCS_PATTERN); + return CPDF_ColorSpace::GetStockCS(CPDF_ColorSpace::Family::kPattern); if (name == "DeviceGray" || name == "DeviceCMYK" || name == "DeviceRGB") { ByteString defname = "Default"; defname += name.Last(name.GetLength() - 7); - const CPDF_Object* pDefObj = FindResourceObj("ColorSpace", defname); + RetainPtr<const CPDF_Object> pDefObj = + FindResourceObj("ColorSpace", defname); if (!pDefObj) { - if (name == "DeviceGray") - return CPDF_ColorSpace::GetStockCS(PDFCS_DEVICEGRAY); - + if (name == "DeviceGray") { + return CPDF_ColorSpace::GetStockCS( + CPDF_ColorSpace::Family::kDeviceGray); + } if (name == "DeviceRGB") - return CPDF_ColorSpace::GetStockCS(PDFCS_DEVICERGB); + return CPDF_ColorSpace::GetStockCS(CPDF_ColorSpace::Family::kDeviceRGB); - return CPDF_ColorSpace::GetStockCS(PDFCS_DEVICECMYK); + return CPDF_ColorSpace::GetStockCS(CPDF_ColorSpace::Family::kDeviceCMYK); } - return CPDF_DocPageData::FromDocument(m_pDocument.Get()) - ->GetColorSpace(pDefObj, nullptr); + return CPDF_DocPageData::FromDocument(m_pDocument) + ->GetColorSpace(pDefObj.Get(), nullptr); } - const CPDF_Object* pCSObj = FindResourceObj("ColorSpace", name); - if (!pCSObj) { - m_bResourceMissing = true; + RetainPtr<const CPDF_Object> pCSObj = FindResourceObj("ColorSpace", name); + if (!pCSObj) return nullptr; - } - return CPDF_DocPageData::FromDocument(m_pDocument.Get()) - ->GetColorSpace(pCSObj, nullptr); + return CPDF_DocPageData::FromDocument(m_pDocument) + ->GetColorSpace(pCSObj.Get(), nullptr); } RetainPtr<CPDF_Pattern> CPDF_StreamContentParser::FindPattern( - const ByteString& name, - bool bShading) { - CPDF_Object* pPattern = - FindResourceObj(bShading ? "Shading" : "Pattern", name); - if (!pPattern || (!pPattern->IsDictionary() && !pPattern->IsStream())) { - m_bResourceMissing = true; + const ByteString& name) { + RetainPtr<CPDF_Object> pPattern = FindResourceObj("Pattern", name); + if (!pPattern || (!pPattern->IsDictionary() && !pPattern->IsStream())) return nullptr; - } - return CPDF_DocPageData::FromDocument(m_pDocument.Get()) - ->GetPattern(pPattern, bShading, m_pCurStates->m_ParentMatrix); + return CPDF_DocPageData::FromDocument(m_pDocument) + ->GetPattern(std::move(pPattern), m_pCurStates->m_ParentMatrix); +} + +RetainPtr<CPDF_ShadingPattern> CPDF_StreamContentParser::FindShading( + const ByteString& name) { + RetainPtr<CPDF_Object> pPattern = FindResourceObj("Shading", name); + if (!pPattern || (!pPattern->IsDictionary() && !pPattern->IsStream())) + return nullptr; + return CPDF_DocPageData::FromDocument(m_pDocument) + ->GetShading(std::move(pPattern), m_pCurStates->m_ParentMatrix); } void CPDF_StreamContentParser::AddTextObject(const ByteString* pStrs, @@ -1225,11 +1239,11 @@ pFont->IsType3Font() ? TextRenderingMode::MODE_FILL : m_pCurStates->m_TextState.GetTextMode(); { - auto pText = pdfium::MakeUnique<CPDF_TextObject>(GetCurrentStreamIndex()); - m_pLastTextObject = pText.get(); - SetGraphicStates(m_pLastTextObject.Get(), true, true, true); + auto pText = std::make_unique<CPDF_TextObject>(GetCurrentStreamIndex()); + pText->SetResourceName(pFont->GetResourceName()); + SetGraphicStates(pText.get(), true, true, true); if (TextRenderingModeIsStrokeMode(text_mode)) { - float* pCTM = pText->m_TextState.GetMutableCTM(); + pdfium::span<float> pCTM = pText->m_TextState.GetMutableCTM(); pCTM[0] = m_pCurStates->m_CTM.a; pCTM[1] = m_pCurStates->m_CTM.c; pCTM[2] = m_pCurStates->m_CTM.b; @@ -1244,10 +1258,8 @@ m_pCurStates->m_TextPos += pText->CalcPositionData(m_pCurStates->m_TextHorzScale); - if (TextRenderingModeIsClipMode(text_mode)) { - m_ClipTextList.push_back( - std::unique_ptr<CPDF_TextObject>(pText->Clone())); - } + if (TextRenderingModeIsClipMode(text_mode)) + m_ClipTextList.push_back(pText->Clone()); m_pObjectHolder->AppendPageObject(std::move(pText)); } if (!kernings.empty() && kernings[nSegs - 1] != 0) { @@ -1280,20 +1292,20 @@ } void CPDF_StreamContentParser::Handle_ShowText_Positioning() { - CPDF_Array* pArray = ToArray(GetObject(0)); + RetainPtr<CPDF_Array> pArray = ToArray(GetObject(0)); if (!pArray) return; size_t n = pArray->size(); size_t nsegs = 0; for (size_t i = 0; i < n; i++) { - const CPDF_Object* pDirectObject = pArray->GetDirectObjectAt(i); + RetainPtr<const CPDF_Object> pDirectObject = pArray->GetDirectObjectAt(i); if (pDirectObject && pDirectObject->IsString()) nsegs++; } if (nsegs == 0) { for (size_t i = 0; i < n; i++) { - float fKerning = pArray->GetNumberAt(i); + float fKerning = pArray->GetFloatAt(i); if (fKerning != 0) m_pCurStates->m_TextPos.x -= GetHorizontalTextSize(fKerning); } @@ -1304,7 +1316,7 @@ size_t iSegment = 0; float fInitKerning = 0; for (size_t i = 0; i < n; i++) { - CPDF_Object* pObj = pArray->GetDirectObjectAt(i); + RetainPtr<const CPDF_Object> pObj = pArray->GetDirectObjectAt(i); if (!pObj) continue; @@ -1330,9 +1342,7 @@ } void CPDF_StreamContentParser::Handle_SetTextMatrix() { - m_pCurStates->m_TextMatrix = - CFX_Matrix(GetNumber(5), GetNumber(4), GetNumber(3), GetNumber(2), - GetNumber(1), GetNumber(0)); + m_pCurStates->m_TextMatrix = GetMatrix(); OnChangeTextMatrix(); m_pCurStates->m_TextPos = CFX_PointF(); m_pCurStates->m_TextLinePos = CFX_PointF(); @@ -1344,7 +1354,8 @@ text_matrix.Concat(m_pCurStates->m_TextMatrix); text_matrix.Concat(m_pCurStates->m_CTM); text_matrix.Concat(m_mtContentToUser); - float* pTextMatrix = m_pCurStates->m_TextState.GetMutableMatrix(); + pdfium::span<float> pTextMatrix = + m_pCurStates->m_TextState.GetMutableMatrix(); pTextMatrix[0] = text_matrix.a; pTextMatrix[1] = text_matrix.c; pTextMatrix[2] = text_matrix.b; @@ -1379,9 +1390,9 @@ } void CPDF_StreamContentParser::Handle_CurveTo_23() { - AddPathPoint(m_PathCurrentX, m_PathCurrentY, FXPT_TYPE::BezierTo, false); - AddPathPoint(GetNumber(3), GetNumber(2), FXPT_TYPE::BezierTo, false); - AddPathPoint(GetNumber(1), GetNumber(0), FXPT_TYPE::BezierTo, false); + AddPathPoint(m_PathCurrent, CFX_Path::Point::Type::kBezier); + AddPathPoint(GetPoint(2), CFX_Path::Point::Type::kBezier); + AddPathPoint(GetPoint(0), CFX_Path::Point::Type::kBezier); } void CPDF_StreamContentParser::Handle_SetLineWidth() { @@ -1389,17 +1400,17 @@ } void CPDF_StreamContentParser::Handle_Clip() { - m_PathClipType = FXFILL_WINDING; + m_PathClipType = CFX_FillRenderOptions::FillType::kWinding; } void CPDF_StreamContentParser::Handle_EOClip() { - m_PathClipType = FXFILL_ALTERNATE; + m_PathClipType = CFX_FillRenderOptions::FillType::kEvenOdd; } void CPDF_StreamContentParser::Handle_CurveTo_13() { - AddPathPoint(GetNumber(3), GetNumber(2), FXPT_TYPE::BezierTo, false); - AddPathPoint(GetNumber(1), GetNumber(0), FXPT_TYPE::BezierTo, false); - AddPathPoint(GetNumber(1), GetNumber(0), FXPT_TYPE::BezierTo, false); + AddPathPoint(GetPoint(2), CFX_Path::Point::Type::kBezier); + AddPathPoint(GetPoint(0), CFX_Path::Point::Type::kBezier); + AddPathPoint(GetPoint(0), CFX_Path::Point::Type::kBezier); } void CPDF_StreamContentParser::Handle_NextLineShowText() { @@ -1415,129 +1426,152 @@ void CPDF_StreamContentParser::Handle_Invalid() {} -void CPDF_StreamContentParser::AddPathPoint(float x, - float y, - FXPT_TYPE type, - bool close) { +void CPDF_StreamContentParser::AddPathPoint(const CFX_PointF& point, + CFX_Path::Point::Type type) { // If the path point is the same move as the previous one and neither of them // closes the path, then just skip it. - if (!close && type == FXPT_TYPE::MoveTo && !m_PathPoints.empty() && + if (type == CFX_Path::Point::Type::kMove && !m_PathPoints.empty() && !m_PathPoints.back().m_CloseFigure && - m_PathPoints.back().m_Type == type && m_PathCurrentX == x && - m_PathCurrentY == y) { + m_PathPoints.back().m_Type == type && m_PathCurrent == point) { return; } - m_PathCurrentX = x; - m_PathCurrentY = y; - if (type == FXPT_TYPE::MoveTo && !close) { - m_PathStartX = x; - m_PathStartY = y; + m_PathCurrent = point; + if (type == CFX_Path::Point::Type::kMove) { + m_PathStart = point; if (!m_PathPoints.empty() && - m_PathPoints.back().IsTypeAndOpen(FXPT_TYPE::MoveTo)) { - m_PathPoints.back().m_Point = CFX_PointF(x, y); + m_PathPoints.back().IsTypeAndOpen(CFX_Path::Point::Type::kMove)) { + m_PathPoints.back().m_Point = point; return; } } else if (m_PathPoints.empty()) { return; } - m_PathPoints.push_back(FX_PATHPOINT(CFX_PointF(x, y), type, close)); + m_PathPoints.emplace_back(point, type, /*close=*/false); } -void CPDF_StreamContentParser::AddPathObject(int FillType, bool bStroke) { - std::vector<FX_PATHPOINT> PathPoints; - PathPoints.swap(m_PathPoints); - uint8_t PathClipType = m_PathClipType; - m_PathClipType = 0; - - if (PathPoints.empty()) +void CPDF_StreamContentParser::AddPathPointAndClose( + const CFX_PointF& point, + CFX_Path::Point::Type type) { + m_PathCurrent = point; + if (m_PathPoints.empty()) return; - if (PathPoints.size() == 1) { - if (PathClipType) { + m_PathPoints.emplace_back(point, type, /*close=*/true); +} + +void CPDF_StreamContentParser::AddPathObject( + CFX_FillRenderOptions::FillType fill_type, + RenderType render_type) { + std::vector<CFX_Path::Point> path_points; + path_points.swap(m_PathPoints); + CFX_FillRenderOptions::FillType path_clip_type = m_PathClipType; + m_PathClipType = CFX_FillRenderOptions::FillType::kNoFill; + + if (path_points.empty()) + return; + + if (path_points.size() == 1) { + if (path_clip_type != CFX_FillRenderOptions::FillType::kNoFill) { CPDF_Path path; path.AppendRect(0, 0, 0, 0); - m_pCurStates->m_ClipPath.AppendPath(path, FXFILL_WINDING, true); + m_pCurStates->m_ClipPath.AppendPathWithAutoMerge( + path, CFX_FillRenderOptions::FillType::kWinding); + return; } - return; + + CFX_Path::Point& point = path_points.front(); + if (point.m_Type != CFX_Path::Point::Type::kMove || !point.m_CloseFigure || + m_pCurStates->m_GraphState.GetLineCap() != + CFX_GraphStateData::LineCap::kRound) { + return; + } + + // For round line cap only: When a path moves to a point and immediately + // gets closed, we can treat it as drawing a path from this point to itself + // and closing the path. This should not apply to butt line cap or + // projecting square line cap since they should not be rendered. + point.m_CloseFigure = false; + path_points.emplace_back(point.m_Point, CFX_Path::Point::Type::kLine, + /*close=*/true); } - if (PathPoints.back().IsTypeAndOpen(FXPT_TYPE::MoveTo)) - PathPoints.pop_back(); + if (path_points.back().IsTypeAndOpen(CFX_Path::Point::Type::kMove)) + path_points.pop_back(); - CPDF_Path Path; - for (const auto& point : PathPoints) - Path.AppendPoint(point.m_Point, point.m_Type, point.m_CloseFigure); + CPDF_Path path; + for (const auto& point : path_points) { + if (point.m_CloseFigure) + path.AppendPointAndClose(point.m_Point, point.m_Type); + else + path.AppendPoint(point.m_Point, point.m_Type); + } CFX_Matrix matrix = m_pCurStates->m_CTM * m_mtContentToUser; - if (bStroke || FillType) { - auto pPathObj = - pdfium::MakeUnique<CPDF_PathObject>(GetCurrentStreamIndex()); + bool bStroke = render_type == RenderType::kStroke; + if (bStroke || fill_type != CFX_FillRenderOptions::FillType::kNoFill) { + auto pPathObj = std::make_unique<CPDF_PathObject>(GetCurrentStreamIndex()); pPathObj->set_stroke(bStroke); - pPathObj->set_filltype(FillType); - pPathObj->path() = Path; - pPathObj->set_matrix(matrix); + pPathObj->set_filltype(fill_type); + pPathObj->path() = path; SetGraphicStates(pPathObj.get(), true, false, true); - pPathObj->CalcBoundingBox(); + pPathObj->SetPathMatrix(matrix); m_pObjectHolder->AppendPageObject(std::move(pPathObj)); } - if (PathClipType) { + if (path_clip_type != CFX_FillRenderOptions::FillType::kNoFill) { if (!matrix.IsIdentity()) - Path.Transform(matrix); - m_pCurStates->m_ClipPath.AppendPath(Path, PathClipType, true); + path.Transform(matrix); + m_pCurStates->m_ClipPath.AppendPathWithAutoMerge(path, path_clip_type); } } uint32_t CPDF_StreamContentParser::Parse( - const uint8_t* pData, - uint32_t dwSize, + pdfium::span<const uint8_t> pData, uint32_t start_offset, uint32_t max_cost, const std::vector<uint32_t>& stream_start_offsets) { - ASSERT(start_offset < dwSize); + DCHECK(start_offset < pData.size()); - // Parsing will be done from |pDataStart|, for at most |size_left| bytes. - const uint8_t* pDataStart = pData + start_offset; - uint32_t size_left = dwSize - start_offset; - + // Parsing will be done from within |pDataStart|. + pdfium::span<const uint8_t> pDataStart = pData.subspan(start_offset); m_StartParseOffset = start_offset; - if (m_ParsedSet->size() > kMaxFormLevel || - pdfium::ContainsKey(*m_ParsedSet, pDataStart)) { - return size_left; + pdfium::Contains(*m_ParsedSet, pDataStart.data())) { + return fxcrt::CollectionSize<uint32_t>(pDataStart); } m_StreamStartOffsets = stream_start_offsets; - pdfium::ScopedSetInsertion<const uint8_t*> scopedInsert(m_ParsedSet.Get(), - pDataStart); + ScopedSetInsertion<const uint8_t*> scopedInsert(m_ParsedSet, + pDataStart.data()); uint32_t init_obj_count = m_pObjectHolder->GetPageObjectCount(); - CPDF_StreamParser syntax(pdfium::make_span(pDataStart, size_left), - m_pDocument->GetByteStringPool()); - CPDF_StreamParserAutoClearer auto_clearer(&m_pSyntax, &syntax); - while (1) { + AutoNuller<std::unique_ptr<CPDF_StreamParser>> auto_clearer(&m_pSyntax); + m_pSyntax = std::make_unique<CPDF_StreamParser>( + pDataStart, m_pDocument->GetByteStringPool()); + + while (true) { uint32_t cost = m_pObjectHolder->GetPageObjectCount() - init_obj_count; if (max_cost && cost >= max_cost) { break; } - switch (syntax.ParseNextElement()) { - case CPDF_StreamParser::EndOfData: + switch (m_pSyntax->ParseNextElement()) { + case CPDF_StreamParser::ElementType::kEndOfData: return m_pSyntax->GetPos(); - case CPDF_StreamParser::Keyword: - OnOperator(syntax.GetWord()); + case CPDF_StreamParser::ElementType::kKeyword: + OnOperator(m_pSyntax->GetWord()); ClearAllParams(); break; - case CPDF_StreamParser::Number: - AddNumberParam(syntax.GetWord()); + case CPDF_StreamParser::ElementType::kNumber: + AddNumberParam(m_pSyntax->GetWord()); break; - case CPDF_StreamParser::Name: { - auto word = syntax.GetWord(); + case CPDF_StreamParser::ElementType::kName: { + auto word = m_pSyntax->GetWord(); AddNameParam(word.Last(word.GetLength() - 1)); break; } default: - AddObjectParam(syntax.GetObject()); + AddObjectParam(m_pSyntax->GetObject()); } } return m_pSyntax->GetPos(); @@ -1547,42 +1581,51 @@ float params[6] = {}; int nParams = 0; int last_pos = m_pSyntax->GetPos(); - while (1) { - CPDF_StreamParser::SyntaxType type = m_pSyntax->ParseNextElement(); + while (true) { + CPDF_StreamParser::ElementType type = m_pSyntax->ParseNextElement(); bool bProcessed = true; switch (type) { - case CPDF_StreamParser::EndOfData: + case CPDF_StreamParser::ElementType::kEndOfData: return; - case CPDF_StreamParser::Keyword: { + case CPDF_StreamParser::ElementType::kKeyword: { ByteStringView strc = m_pSyntax->GetWord(); int len = strc.GetLength(); if (len == 1) { switch (strc[0]) { case kPathOperatorSubpath: - AddPathPoint(params[0], params[1], FXPT_TYPE::MoveTo, false); + AddPathPoint({params[0], params[1]}, + CFX_Path::Point::Type::kMove); nParams = 0; break; case kPathOperatorLine: - AddPathPoint(params[0], params[1], FXPT_TYPE::LineTo, false); + AddPathPoint({params[0], params[1]}, + CFX_Path::Point::Type::kLine); nParams = 0; break; case kPathOperatorCubicBezier1: - AddPathPoint(params[0], params[1], FXPT_TYPE::BezierTo, false); - AddPathPoint(params[2], params[3], FXPT_TYPE::BezierTo, false); - AddPathPoint(params[4], params[5], FXPT_TYPE::BezierTo, false); + AddPathPoint({params[0], params[1]}, + CFX_Path::Point::Type::kBezier); + AddPathPoint({params[2], params[3]}, + CFX_Path::Point::Type::kBezier); + AddPathPoint({params[4], params[5]}, + CFX_Path::Point::Type::kBezier); nParams = 0; break; case kPathOperatorCubicBezier2: - AddPathPoint(m_PathCurrentX, m_PathCurrentY, FXPT_TYPE::BezierTo, - false); - AddPathPoint(params[0], params[1], FXPT_TYPE::BezierTo, false); - AddPathPoint(params[2], params[3], FXPT_TYPE::BezierTo, false); + AddPathPoint(m_PathCurrent, CFX_Path::Point::Type::kBezier); + AddPathPoint({params[0], params[1]}, + CFX_Path::Point::Type::kBezier); + AddPathPoint({params[2], params[3]}, + CFX_Path::Point::Type::kBezier); nParams = 0; break; case kPathOperatorCubicBezier3: - AddPathPoint(params[0], params[1], FXPT_TYPE::BezierTo, false); - AddPathPoint(params[2], params[3], FXPT_TYPE::BezierTo, false); - AddPathPoint(params[2], params[3], FXPT_TYPE::BezierTo, false); + AddPathPoint({params[0], params[1]}, + CFX_Path::Point::Type::kBezier); + AddPathPoint({params[2], params[3]}, + CFX_Path::Point::Type::kBezier); + AddPathPoint({params[2], params[3]}, + CFX_Path::Point::Type::kBezier); nParams = 0; break; case kPathOperatorClosePath: @@ -1609,7 +1652,7 @@ } break; } - case CPDF_StreamParser::Number: { + case CPDF_StreamParser::ElementType::kNumber: { if (nParams == 6) break; @@ -1630,15 +1673,15 @@ // static ByteStringView CPDF_StreamContentParser::FindKeyAbbreviationForTesting( ByteStringView abbr) { - return FindFullName(kInlineKeyAbbr, FX_ArraySize(kInlineKeyAbbr), abbr); + return FindFullName(kInlineKeyAbbr, abbr); } // static ByteStringView CPDF_StreamContentParser::FindValueAbbreviationForTesting( ByteStringView abbr) { - return FindFullName(kInlineValueAbbr, FX_ArraySize(kInlineValueAbbr), abbr); + return FindFullName(kInlineValueAbbr, abbr); } -CPDF_StreamContentParser::ContentParam::ContentParam() {} +CPDF_StreamContentParser::ContentParam::ContentParam() = default; -CPDF_StreamContentParser::ContentParam::~ContentParam() {} +CPDF_StreamContentParser::ContentParam::~ContentParam() = default;
diff --git a/core/fpdfapi/page/cpdf_streamcontentparser.h b/core/fpdfapi/page/cpdf_streamcontentparser.h index a270320..276dc72 100644 --- a/core/fpdfapi/page/cpdf_streamcontentparser.h +++ b/core/fpdfapi/page/cpdf_streamcontentparser.h
@@ -1,4 +1,4 @@ -// Copyright 2016 PDFium Authors. All rights reserved. +// Copyright 2016 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -14,10 +14,14 @@ #include <vector> #include "core/fpdfapi/page/cpdf_contentmarks.h" +#include "core/fxcrt/bytestring.h" +#include "core/fxcrt/fx_coordinates.h" #include "core/fxcrt/fx_number.h" -#include "core/fxcrt/fx_string.h" #include "core/fxcrt/retain_ptr.h" -#include "core/fxge/cfx_pathdata.h" +#include "core/fxcrt/unowned_ptr.h" +#include "core/fxge/cfx_fillrenderoptions.h" +#include "core/fxge/cfx_path.h" +#include "third_party/base/span.h" class CPDF_AllStates; class CPDF_ColorSpace; @@ -30,6 +34,7 @@ class CPDF_PageObject; class CPDF_PageObjectHolder; class CPDF_Pattern; +class CPDF_ShadingPattern; class CPDF_Stream; class CPDF_StreamParser; class CPDF_TextObject; @@ -37,46 +42,45 @@ class CPDF_StreamContentParser { public: CPDF_StreamContentParser(CPDF_Document* pDoc, - CPDF_Dictionary* pPageResources, - CPDF_Dictionary* pParentResources, + RetainPtr<CPDF_Dictionary> pPageResources, + RetainPtr<CPDF_Dictionary> pParentResources, const CFX_Matrix* pmtContentToUser, CPDF_PageObjectHolder* pObjHolder, - CPDF_Dictionary* pResources, + RetainPtr<CPDF_Dictionary> pResources, const CFX_FloatRect& rcBBox, const CPDF_AllStates* pStates, std::set<const uint8_t*>* pParsedSet); ~CPDF_StreamContentParser(); - uint32_t Parse(const uint8_t* pData, - uint32_t dwSize, + uint32_t Parse(pdfium::span<const uint8_t> pData, uint32_t start_offset, uint32_t max_cost, const std::vector<uint32_t>& stream_start_offsets); - CPDF_PageObjectHolder* GetPageObjectHolder() const { - return m_pObjectHolder.Get(); - } + CPDF_PageObjectHolder* GetPageObjectHolder() const { return m_pObjectHolder; } CPDF_AllStates* GetCurStates() const { return m_pCurStates.get(); } bool IsColored() const { return m_bColored; } - const float* GetType3Data() const { return m_Type3Data; } + pdfium::span<const float> GetType3Data() const { return m_Type3Data; } RetainPtr<CPDF_Font> FindFont(const ByteString& name); static ByteStringView FindKeyAbbreviationForTesting(ByteStringView abbr); static ByteStringView FindValueAbbreviationForTesting(ByteStringView abbr); private: + enum class RenderType : bool { kFill = false, kStroke = true }; + struct ContentParam { - enum Type { OBJECT = 0, NUMBER, NAME }; + enum class Type : uint8_t { kObject = 0, kNumber, kName }; ContentParam(); ~ContentParam(); - Type m_Type; + Type m_Type = Type::kObject; FX_Number m_Number; ByteString m_Name; RetainPtr<CPDF_Object> m_pObject; }; - static const int kParamBufSize = 16; + static constexpr int kParamBufSize = 16; using OpCodes = std::map<uint32_t, void (CPDF_StreamContentParser::*)()>; static OpCodes InitializeOpCodes(); @@ -86,7 +90,7 @@ void AddObjectParam(RetainPtr<CPDF_Object> pObj); int GetNextParamPos(); void ClearAllParams(); - CPDF_Object* GetObject(uint32_t index); + RetainPtr<CPDF_Object> GetObject(uint32_t index); ByteString GetString(uint32_t index) const; float GetNumber(uint32_t index) const; // Calls GetNumber() |count| times and returns the values in reverse order. @@ -95,6 +99,10 @@ int GetInteger(uint32_t index) const { return static_cast<int>(GetNumber(index)); } + // Makes a point from {GetNumber(index + 1), GetNumber(index)}. + CFX_PointF GetPoint(uint32_t index) const; + // Makes a matrix from {GetNumber(5), ..., GetNumber(0)}. + CFX_Matrix GetMatrix() const; void OnOperator(ByteStringView op); void AddTextObject(const ByteString* pStrs, float fInitKerning, @@ -105,22 +113,29 @@ void OnChangeTextMatrix(); void ParsePathObject(); - void AddPathPoint(float x, float y, FXPT_TYPE type, bool close); + void AddPathPoint(const CFX_PointF& point, CFX_Path::Point::Type type); + void AddPathPointAndClose(const CFX_PointF& point, + CFX_Path::Point::Type type); void AddPathRect(float x, float y, float w, float h); - void AddPathObject(int FillType, bool bStroke); - CPDF_ImageObject* AddImage(RetainPtr<CPDF_Stream> pStream); - CPDF_ImageObject* AddImage(uint32_t streamObjNum); - CPDF_ImageObject* AddImage(const RetainPtr<CPDF_Image>& pImage); + void AddPathObject(CFX_FillRenderOptions::FillType fill_type, + RenderType render_type); + CPDF_ImageObject* AddImageFromStream(RetainPtr<CPDF_Stream> pStream, + const ByteString& name); + CPDF_ImageObject* AddImageFromStreamObjNum(uint32_t stream_obj_num, + const ByteString& name); + CPDF_ImageObject* AddLastImage(); - void AddForm(CPDF_Stream* pStream); + void AddForm(RetainPtr<CPDF_Stream> pStream, const ByteString& name); void SetGraphicStates(CPDF_PageObject* pObj, bool bColor, bool bText, bool bGraph); RetainPtr<CPDF_ColorSpace> FindColorSpace(const ByteString& name); - RetainPtr<CPDF_Pattern> FindPattern(const ByteString& name, bool bShading); - CPDF_Dictionary* FindResourceHolder(const ByteString& type); - CPDF_Object* FindResourceObj(const ByteString& type, const ByteString& name); + RetainPtr<CPDF_Pattern> FindPattern(const ByteString& name); + RetainPtr<CPDF_ShadingPattern> FindShading(const ByteString& name); + RetainPtr<CPDF_Dictionary> FindResourceHolder(const ByteString& type); + RetainPtr<CPDF_Object> FindResourceObj(const ByteString& type, + const ByteString& name); // Takes ownership of |pImageObj|, returns unowned pointer to it. CPDF_ImageObject* AddImageObject(std::unique_ptr<CPDF_ImageObject> pImageObj); @@ -212,21 +227,18 @@ const CFX_FloatRect m_BBox; uint32_t m_ParamStartPos = 0; uint32_t m_ParamCount = 0; - UnownedPtr<CPDF_StreamParser> m_pSyntax; + std::unique_ptr<CPDF_StreamParser> m_pSyntax; std::unique_ptr<CPDF_AllStates> m_pCurStates; std::stack<std::unique_ptr<CPDF_ContentMarks>> m_ContentMarksStack; std::vector<std::unique_ptr<CPDF_TextObject>> m_ClipTextList; - UnownedPtr<CPDF_TextObject> m_pLastTextObject; - std::vector<FX_PATHPOINT> m_PathPoints; - float m_PathStartX = 0.0f; - float m_PathStartY = 0.0f; - float m_PathCurrentX = 0.0f; - float m_PathCurrentY = 0.0f; - uint8_t m_PathClipType = 0; + std::vector<CFX_Path::Point> m_PathPoints; + CFX_PointF m_PathStart; + CFX_PointF m_PathCurrent; + CFX_FillRenderOptions::FillType m_PathClipType = + CFX_FillRenderOptions::FillType::kNoFill; ByteString m_LastImageName; RetainPtr<CPDF_Image> m_pLastImage; bool m_bColored = false; - bool m_bResourceMissing = false; std::vector<std::unique_ptr<CPDF_AllStates>> m_StateStack; float m_Type3Data[6] = {0.0f}; ContentParam m_ParamBuf[kParamBufSize];
diff --git a/core/fpdfapi/page/cpdf_streamcontentparser_unittest.cpp b/core/fpdfapi/page/cpdf_streamcontentparser_unittest.cpp index 0f4fc1e..8198daf 100644 --- a/core/fpdfapi/page/cpdf_streamcontentparser_unittest.cpp +++ b/core/fpdfapi/page/cpdf_streamcontentparser_unittest.cpp
@@ -1,4 +1,4 @@ -// Copyright 2016 PDFium Authors. All rights reserved. +// Copyright 2016 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file.
diff --git a/core/fpdfapi/page/cpdf_streamparser.cpp b/core/fpdfapi/page/cpdf_streamparser.cpp index 25172a6..dd0a76d 100644 --- a/core/fpdfapi/page/cpdf_streamparser.cpp +++ b/core/fpdfapi/page/cpdf_streamparser.cpp
@@ -1,4 +1,4 @@ -// Copyright 2016 PDFium Authors. All rights reserved. +// Copyright 2016 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -6,11 +6,10 @@ #include "core/fpdfapi/page/cpdf_streamparser.h" -#include <limits.h> +#include <ctype.h> #include <algorithm> #include <memory> -#include <sstream> #include <utility> #include "constants/stream_dict_common.h" @@ -18,7 +17,6 @@ #include "core/fpdfapi/parser/cpdf_array.h" #include "core/fpdfapi/parser/cpdf_boolean.h" #include "core/fpdfapi/parser/cpdf_dictionary.h" -#include "core/fpdfapi/parser/cpdf_document.h" #include "core/fpdfapi/parser/cpdf_name.h" #include "core/fpdfapi/parser/cpdf_null.h" #include "core/fpdfapi/parser/cpdf_number.h" @@ -26,13 +24,15 @@ #include "core/fpdfapi/parser/cpdf_string.h" #include "core/fpdfapi/parser/fpdf_parser_decode.h" #include "core/fpdfapi/parser/fpdf_parser_utility.h" -#include "core/fxcodec/fx_codec.h" #include "core/fxcodec/jpeg/jpegmodule.h" #include "core/fxcodec/scanlinedecoder.h" +#include "core/fxcrt/data_vector.h" #include "core/fxcrt/fx_extension.h" #include "core/fxcrt/fx_memory_wrappers.h" #include "core/fxcrt/fx_safe_types.h" -#include "third_party/base/ptr_util.h" +#include "core/fxcrt/span_util.h" +#include "core/fxge/calculate_pitch.h" +#include "third_party/base/check.h" namespace { @@ -54,13 +54,18 @@ if (width <= 0 || height <= 0) return FX_INVALID_OFFSET; - FX_SAFE_UINT32 size = fxcodec::CalculatePitch8(bpc, ncomps, width); + absl::optional<uint32_t> maybe_size = + fxge::CalculatePitch8(bpc, ncomps, width); + if (!maybe_size.has_value()) + return FX_INVALID_OFFSET; + + FX_SAFE_UINT32 size = maybe_size.value(); size *= height; if (size.ValueOrDefault(0) == 0) return FX_INVALID_OFFSET; for (int row = 0; row < height; ++row) { - if (!pDecoder->GetScanline(row)) + if (pDecoder->GetScanline(row).empty()) break; } return pDecoder->GetSrcOffset(); @@ -70,37 +75,36 @@ int width, int height, const ByteString& decoder, - const CPDF_Dictionary* pParam, + RetainPtr<const CPDF_Dictionary> pParam, uint32_t orig_size) { // |decoder| should not be an abbreviation. - ASSERT(decoder != "A85"); - ASSERT(decoder != "AHx"); - ASSERT(decoder != "CCF"); - ASSERT(decoder != "DCT"); - ASSERT(decoder != "Fl"); - ASSERT(decoder != "LZW"); - ASSERT(decoder != "RL"); + DCHECK(decoder != "A85"); + DCHECK(decoder != "AHx"); + DCHECK(decoder != "CCF"); + DCHECK(decoder != "DCT"); + DCHECK(decoder != "Fl"); + DCHECK(decoder != "LZW"); + DCHECK(decoder != "RL"); std::unique_ptr<uint8_t, FxFreeDeleter> ignored_result; uint32_t ignored_size; if (decoder == "FlateDecode") { - return FlateOrLZWDecode(false, src_span, pParam, orig_size, &ignored_result, - &ignored_size); + return FlateOrLZWDecode(false, src_span, pParam.Get(), orig_size, + &ignored_result, &ignored_size); } if (decoder == "LZWDecode") { - return FlateOrLZWDecode(true, src_span, pParam, 0, &ignored_result, + return FlateOrLZWDecode(true, src_span, pParam.Get(), 0, &ignored_result, &ignored_size); } if (decoder == "DCTDecode") { - std::unique_ptr<ScanlineDecoder> pDecoder = - fxcodec::ModuleMgr::GetInstance()->GetJpegModule()->CreateDecoder( - src_span, width, height, 0, - !pParam || pParam->GetIntegerFor("ColorTransform", 1)); + std::unique_ptr<ScanlineDecoder> pDecoder = JpegModule::CreateDecoder( + src_span, width, height, 0, + !pParam || pParam->GetIntegerFor("ColorTransform", 1)); return DecodeAllScanlines(std::move(pDecoder)); } if (decoder == "CCITTFaxDecode") { std::unique_ptr<ScanlineDecoder> pDecoder = - CreateFaxDecoder(src_span, width, height, pParam); + CreateFaxDecoder(src_span, width, height, pParam.Get()); return DecodeAllScanlines(std::move(pDecoder)); } @@ -123,7 +127,7 @@ const WeakPtr<ByteStringPool>& pPool) : m_pPool(pPool), m_pBuf(span) {} -CPDF_StreamParser::~CPDF_StreamParser() {} +CPDF_StreamParser::~CPDF_StreamParser() = default; RetainPtr<CPDF_Stream> CPDF_StreamParser::ReadInlineStream( CPDF_Document* pDoc, @@ -136,13 +140,13 @@ return nullptr; ByteString decoder; - const CPDF_Dictionary* pParam = nullptr; - CPDF_Object* pFilter = pDict->GetDirectObjectFor("Filter"); + RetainPtr<const CPDF_Dictionary> pParam; + RetainPtr<const CPDF_Object> pFilter = pDict->GetDirectObjectFor("Filter"); if (pFilter) { const CPDF_Array* pArray = pFilter->AsArray(); if (pArray) { - decoder = pArray->GetStringAt(0); - const CPDF_Array* pParams = + decoder = pArray->GetByteStringAt(0); + RetainPtr<const CPDF_Array> pParams = pDict->GetArrayFor(pdfium::stream::kDecodeParms); if (pParams) pParam = pParams->GetDictAt(0); @@ -161,36 +165,40 @@ nComponents = pCS ? pCS->CountComponents() : 3; bpc = pDict->GetIntegerFor("BitsPerComponent"); } - FX_SAFE_UINT32 size = fxcodec::CalculatePitch8(bpc, nComponents, width); + absl::optional<uint32_t> maybe_size = + fxge::CalculatePitch8(bpc, nComponents, width); + if (!maybe_size.has_value()) + return nullptr; + + FX_SAFE_UINT32 size = maybe_size.value(); size *= height; if (!size.IsValid()) return nullptr; uint32_t dwOrigSize = size.ValueOrDie(); - std::unique_ptr<uint8_t, FxFreeDeleter> pData; + DataVector<uint8_t> data; uint32_t dwStreamSize; if (decoder.IsEmpty()) { dwOrigSize = std::min<uint32_t>(dwOrigSize, m_pBuf.size() - m_Pos); - pData.reset(FX_Alloc(uint8_t, dwOrigSize)); - auto copy_span = m_pBuf.subspan(m_Pos, dwOrigSize); - memcpy(pData.get(), copy_span.data(), copy_span.size()); + auto src_span = m_pBuf.subspan(m_Pos, dwOrigSize); + data = DataVector<uint8_t>(src_span.begin(), src_span.end()); dwStreamSize = dwOrigSize; m_Pos += dwOrigSize; } else { dwStreamSize = DecodeInlineStream(m_pBuf.subspan(m_Pos), width, height, - decoder, pParam, dwOrigSize); + decoder, std::move(pParam), dwOrigSize); if (!pdfium::base::IsValueInRangeForNumericType<int>(dwStreamSize)) return nullptr; uint32_t dwSavePos = m_Pos; m_Pos += dwStreamSize; - while (1) { + while (true) { uint32_t dwPrevPos = m_Pos; - CPDF_StreamParser::SyntaxType type = ParseNextElement(); - if (type == CPDF_StreamParser::EndOfData) + ElementType type = ParseNextElement(); + if (type == ElementType::kEndOfData) break; - if (type != CPDF_StreamParser::Keyword) { + if (type != ElementType::kKeyword) { dwStreamSize += m_Pos - dwPrevPos; continue; } @@ -201,27 +209,25 @@ dwStreamSize += m_Pos - dwPrevPos; } m_Pos = dwSavePos; - pData.reset(FX_Alloc(uint8_t, dwStreamSize)); - auto copy_span = m_pBuf.subspan(m_Pos, dwStreamSize); - memcpy(pData.get(), copy_span.data(), copy_span.size()); + auto src_span = m_pBuf.subspan(m_Pos, dwStreamSize); + data = DataVector<uint8_t>(src_span.begin(), src_span.end()); m_Pos += dwStreamSize; } pDict->SetNewFor<CPDF_Number>("Length", static_cast<int>(dwStreamSize)); - return pdfium::MakeRetain<CPDF_Stream>(std::move(pData), dwStreamSize, - std::move(pDict)); + return pdfium::MakeRetain<CPDF_Stream>(std::move(data), std::move(pDict)); } -CPDF_StreamParser::SyntaxType CPDF_StreamParser::ParseNextElement() { +CPDF_StreamParser::ElementType CPDF_StreamParser::ParseNextElement() { m_pLastObj.Reset(); m_WordSize = 0; if (!PositionIsInBounds()) - return EndOfData; + return ElementType::kEndOfData; uint8_t ch = m_pBuf[m_Pos++]; - while (1) { + while (true) { while (PDFCharIsWhitespace(ch)) { if (!PositionIsInBounds()) - return EndOfData; + return ElementType::kEndOfData; ch = m_pBuf[m_Pos++]; } @@ -229,9 +235,9 @@ if (ch != '%') break; - while (1) { + while (true) { if (!PositionIsInBounds()) - return EndOfData; + return ElementType::kEndOfData; ch = m_pBuf[m_Pos++]; if (PDFCharIsLineEnding(ch)) @@ -242,11 +248,11 @@ if (PDFCharIsDelimiter(ch) && ch != '/') { m_Pos--; m_pLastObj = ReadNextObject(false, false, 0); - return Others; + return ElementType::kOther; } bool bIsNumber = true; - while (1) { + while (true) { if (m_WordSize < kMaxWordLength) m_WordBuffer[m_WordSize++] = ch; @@ -266,27 +272,27 @@ m_WordBuffer[m_WordSize] = 0; if (bIsNumber) - return Number; + return ElementType::kNumber; if (m_WordBuffer[0] == '/') - return Name; + return ElementType::kName; if (m_WordSize == 4) { - if (WordBufferMatches(kTrue)) { + if (GetWord() == kTrue) { m_pLastObj = pdfium::MakeRetain<CPDF_Boolean>(true); - return Others; + return ElementType::kOther; } - if (WordBufferMatches(kNull)) { + if (GetWord() == kNull) { m_pLastObj = pdfium::MakeRetain<CPDF_Null>(); - return Others; + return ElementType::kOther; } } else if (m_WordSize == 5) { - if (WordBufferMatches(kFalse)) { + if (GetWord() == kFalse) { m_pLastObj = pdfium::MakeRetain<CPDF_Boolean>(false); - return Others; + return ElementType::kOther; } } - return Keyword; + return ElementType::kKeyword; } RetainPtr<CPDF_Object> CPDF_StreamParser::ReadNextObject( @@ -301,14 +307,12 @@ if (bIsNumber) { m_WordBuffer[m_WordSize] = 0; - return pdfium::MakeRetain<CPDF_Number>( - ByteStringView(m_WordBuffer, m_WordSize)); + return pdfium::MakeRetain<CPDF_Number>(GetWord()); } int first_char = m_WordBuffer[0]; if (first_char == '/') { - ByteString name = - PDF_NameDecode(ByteStringView(m_WordBuffer + 1, m_WordSize - 1)); + ByteString name = PDF_NameDecode(GetWord().Substr(1)); return pdfium::MakeRetain<CPDF_Name>(m_pPool, name); } @@ -322,7 +326,7 @@ return pdfium::MakeRetain<CPDF_String>(m_pPool, ReadHexString(), true); auto pDict = pdfium::MakeRetain<CPDF_Dictionary>(m_pPool); - while (1) { + while (true) { GetNextWord(bIsNumber); if (m_WordSize == 2 && m_WordBuffer[0] == '>') break; @@ -330,15 +334,13 @@ if (!m_WordSize || m_WordBuffer[0] != '/') return nullptr; - ByteString key = - PDF_NameDecode(ByteStringView(m_WordBuffer + 1, m_WordSize - 1)); + ByteString key = PDF_NameDecode(GetWord().Substr(1)); RetainPtr<CPDF_Object> pObj = ReadNextObject(true, bInArray, dwRecursionLevel + 1); if (!pObj) return nullptr; - if (!key.IsEmpty()) - pDict->SetFor(key, std::move(pObj)); + pDict->SetFor(key, std::move(pObj)); } return pDict; } @@ -348,11 +350,11 @@ return nullptr; auto pArray = pdfium::MakeRetain<CPDF_Array>(); - while (1) { + while (true) { RetainPtr<CPDF_Object> pObj = ReadNextObject(bAllowNestedArray, true, dwRecursionLevel + 1); if (pObj) { - pArray->Add(std::move(pObj)); + pArray->Append(std::move(pObj)); continue; } if (!m_WordSize || m_WordBuffer[0] == ']') @@ -361,11 +363,11 @@ return pArray; } - if (WordBufferMatches(kFalse)) + if (GetWord() == kFalse) return pdfium::MakeRetain<CPDF_Boolean>(false); - if (WordBufferMatches(kTrue)) + if (GetWord() == kTrue) return pdfium::MakeRetain<CPDF_Boolean>(true); - if (WordBufferMatches(kNull)) + if (GetWord() == kNull) return pdfium::MakeRetain<CPDF_Null>(); return nullptr; } @@ -378,7 +380,7 @@ return; uint8_t ch = m_pBuf[m_Pos++]; - while (1) { + while (true) { while (PDFCharIsWhitespace(ch)) { if (!PositionIsInBounds()) { return; @@ -389,7 +391,7 @@ if (ch != '%') break; - while (1) { + while (true) { if (!PositionIsInBounds()) return; ch = m_pBuf[m_Pos++]; @@ -402,7 +404,7 @@ bIsNumber = false; m_WordBuffer[m_WordSize++] = ch; if (ch == '/') { - while (1) { + while (true) { if (!PositionIsInBounds()) return; ch = m_pBuf[m_Pos++]; @@ -433,7 +435,7 @@ return; } - while (1) { + while (true) { if (m_WordSize < kMaxWordLength) m_WordBuffer[m_WordSize++] = ch; if (!PDFCharIsNumeric(ch)) @@ -453,32 +455,27 @@ if (!PositionIsInBounds()) return ByteString(); - uint8_t ch = m_pBuf[m_Pos++]; - std::ostringstream buf; + ByteString buf; int parlevel = 0; int status = 0; int iEscCode = 0; - while (1) { + uint8_t ch = m_pBuf[m_Pos++]; + while (true) { switch (status) { case 0: if (ch == ')') { if (parlevel == 0) { - if (buf.tellp() <= 0) - return ByteString(); - - return ByteString( - buf.str().c_str(), - std::min(static_cast<size_t>(buf.tellp()), kMaxStringLength)); + return buf.First(std::min(buf.GetLength(), kMaxStringLength)); } parlevel--; - buf << ')'; + buf += ')'; } else if (ch == '(') { parlevel++; - buf << '('; + buf += '('; } else if (ch == '\\') { status = 1; } else { - buf << static_cast<char>(ch); + buf += static_cast<char>(ch); } break; case 1: @@ -494,17 +491,17 @@ if (ch == '\n') { // Do nothing. } else if (ch == 'n') { - buf << '\n'; + buf += '\n'; } else if (ch == 'r') { - buf << '\r'; + buf += '\r'; } else if (ch == 't') { - buf << '\t'; + buf += '\t'; } else if (ch == 'b') { - buf << '\b'; + buf += '\b'; } else if (ch == 'f') { - buf << '\f'; + buf += '\f'; } else { - buf << static_cast<char>(ch); + buf += static_cast<char>(ch); } status = 0; break; @@ -514,7 +511,7 @@ iEscCode * 8 + FXSYS_DecimalCharToInt(static_cast<char>(ch)); status = 3; } else { - buf << static_cast<char>(iEscCode); + buf += static_cast<char>(iEscCode); status = 0; continue; } @@ -523,10 +520,10 @@ if (FXSYS_IsOctalDigit(ch)) { iEscCode = iEscCode * 8 + FXSYS_DecimalCharToInt(static_cast<char>(ch)); - buf << static_cast<char>(iEscCode); + buf += static_cast<char>(iEscCode); status = 0; } else { - buf << static_cast<char>(iEscCode); + buf += static_cast<char>(iEscCode); status = 0; continue; } @@ -538,26 +535,17 @@ break; } if (!PositionIsInBounds()) - break; + return buf.First(std::min(buf.GetLength(), kMaxStringLength)); ch = m_pBuf[m_Pos++]; } - if (PositionIsInBounds()) - ++m_Pos; - - if (buf.tellp() <= 0) - return ByteString(); - - return ByteString( - buf.str().c_str(), - std::min(static_cast<size_t>(buf.tellp()), kMaxStringLength)); } ByteString CPDF_StreamParser::ReadHexString() { if (!PositionIsInBounds()) return ByteString(); - std::ostringstream buf; + ByteString buf; bool bFirst = true; int code = 0; while (PositionIsInBounds()) { @@ -565,7 +553,7 @@ if (ch == '>') break; - if (!std::isxdigit(ch)) + if (!isxdigit(ch)) continue; int val = FXSYS_HexCharToInt(ch); @@ -573,26 +561,16 @@ code = val * 16; } else { code += val; - buf << static_cast<uint8_t>(code); + buf += static_cast<uint8_t>(code); } bFirst = !bFirst; } if (!bFirst) - buf << static_cast<char>(code); + buf += static_cast<char>(code); - if (buf.tellp() <= 0) - return ByteString(); - - return ByteString( - buf.str().c_str(), - std::min(static_cast<size_t>(buf.tellp()), kMaxStringLength)); + return buf.First(std::min<size_t>(buf.GetLength(), kMaxStringLength)); } bool CPDF_StreamParser::PositionIsInBounds() const { return m_Pos < m_pBuf.size(); } - -bool CPDF_StreamParser::WordBufferMatches(const char* pWord) const { - const size_t iLength = strlen(pWord); - return m_WordSize == iLength && memcmp(m_WordBuffer, pWord, iLength) == 0; -}
diff --git a/core/fpdfapi/page/cpdf_streamparser.h b/core/fpdfapi/page/cpdf_streamparser.h index 6051b8c..1a0f115 100644 --- a/core/fpdfapi/page/cpdf_streamparser.h +++ b/core/fpdfapi/page/cpdf_streamparser.h
@@ -1,4 +1,4 @@ -// Copyright 2016 PDFium Authors. All rights reserved. +// Copyright 2016 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -7,28 +7,26 @@ #ifndef CORE_FPDFAPI_PAGE_CPDF_STREAMPARSER_H_ #define CORE_FPDFAPI_PAGE_CPDF_STREAMPARSER_H_ -#include <memory> -#include <utility> - -#include "core/fpdfapi/parser/cpdf_document.h" +#include "core/fxcrt/retain_ptr.h" #include "core/fxcrt/string_pool_template.h" #include "core/fxcrt/weak_ptr.h" #include "third_party/base/span.h" class CPDF_Dictionary; +class CPDF_Document; class CPDF_Object; class CPDF_Stream; class CPDF_StreamParser { public: - enum SyntaxType { EndOfData, Number, Keyword, Name, Others }; + enum ElementType { kEndOfData, kNumber, kKeyword, kName, kOther }; explicit CPDF_StreamParser(pdfium::span<const uint8_t> span); CPDF_StreamParser(pdfium::span<const uint8_t> span, const WeakPtr<ByteStringPool>& pPool); ~CPDF_StreamParser(); - SyntaxType ParseNextElement(); + ElementType ParseNextElement(); ByteStringView GetWord() const { return ByteStringView(m_WordBuffer, m_WordSize); } @@ -44,20 +42,19 @@ private: friend class cpdf_streamparser_ReadHexString_Test; - static const uint32_t kMaxWordLength = 255; + static constexpr uint32_t kMaxWordLength = 255; void GetNextWord(bool& bIsNumber); ByteString ReadString(); ByteString ReadHexString(); bool PositionIsInBounds() const; - bool WordBufferMatches(const char* pWord) const; uint32_t m_Pos = 0; // Current byte position within |m_pBuf|. uint32_t m_WordSize = 0; // Current byte position within |m_WordBuffer|. WeakPtr<ByteStringPool> m_pPool; RetainPtr<CPDF_Object> m_pLastObj; pdfium::span<const uint8_t> m_pBuf; - uint8_t m_WordBuffer[kMaxWordLength + 1]; // Include space for NUL. + uint8_t m_WordBuffer[kMaxWordLength + 1] = {}; // Include space for NUL. }; #endif // CORE_FPDFAPI_PAGE_CPDF_STREAMPARSER_H_
diff --git a/core/fpdfapi/page/cpdf_streamparser_unittest.cpp b/core/fpdfapi/page/cpdf_streamparser_unittest.cpp index 64bb57c..c9af44b 100644 --- a/core/fpdfapi/page/cpdf_streamparser_unittest.cpp +++ b/core/fpdfapi/page/cpdf_streamparser_unittest.cpp
@@ -1,4 +1,4 @@ -// Copyright 2015 PDFium Authors. All rights reserved. +// Copyright 2015 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file.
diff --git a/core/fpdfapi/page/cpdf_textobject.cpp b/core/fpdfapi/page/cpdf_textobject.cpp index 077e5ed..a063541 100644 --- a/core/fpdfapi/page/cpdf_textobject.cpp +++ b/core/fpdfapi/page/cpdf_textobject.cpp
@@ -1,4 +1,4 @@ -// Copyright 2016 PDFium Authors. All rights reserved. +// Copyright 2016 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -7,55 +7,62 @@ #include "core/fpdfapi/page/cpdf_textobject.h" #include <algorithm> -#include <utility> #include "core/fpdfapi/font/cpdf_cidfont.h" #include "core/fpdfapi/font/cpdf_font.h" -#include "third_party/base/ptr_util.h" +#include "core/fxcrt/fx_coordinates.h" +#include "third_party/base/check.h" +#include "third_party/base/span.h" #define ISLATINWORD(u) (u != 0x20 && u <= 0x28FF) -CPDF_TextObjectItem::CPDF_TextObjectItem() : m_CharCode(0) {} +namespace { -CPDF_TextObjectItem::~CPDF_TextObjectItem() = default; +bool IsVertWritingCIDFont(const CPDF_CIDFont* font) { + return font && font->IsVertWriting(); +} + +} // namespace + +CPDF_TextObject::Item::Item() = default; + +CPDF_TextObject::Item::Item(const Item& that) = default; + +CPDF_TextObject::Item::~Item() = default; CPDF_TextObject::CPDF_TextObject(int32_t content_stream) : CPDF_PageObject(content_stream) {} CPDF_TextObject::CPDF_TextObject() : CPDF_TextObject(kNoContentStream) {} -CPDF_TextObject::~CPDF_TextObject() { - // Move m_CharCodes to a local variable so it will be captured in crash dumps, - // to help with investigating crbug.com/782215. - auto char_codes_copy = std::move(m_CharCodes); -} +CPDF_TextObject::~CPDF_TextObject() = default; size_t CPDF_TextObject::CountItems() const { return m_CharCodes.size(); } -void CPDF_TextObject::GetItemInfo(size_t index, - CPDF_TextObjectItem* pInfo) const { - ASSERT(index < m_CharCodes.size()); - pInfo->m_CharCode = m_CharCodes[index]; - pInfo->m_Origin = CFX_PointF(index > 0 ? m_CharPos[index - 1] : 0, 0); - if (pInfo->m_CharCode == CPDF_Font::kInvalidCharCode) - return; +CPDF_TextObject::Item CPDF_TextObject::GetItemInfo(size_t index) const { + DCHECK(index < m_CharCodes.size()); + + Item info; + info.m_CharCode = m_CharCodes[index]; + info.m_Origin = CFX_PointF(index > 0 ? m_CharPos[index - 1] : 0, 0); + if (info.m_CharCode == CPDF_Font::kInvalidCharCode) + return info; RetainPtr<CPDF_Font> pFont = GetFont(); - if (!pFont->IsCIDFont() || !pFont->AsCIDFont()->IsVertWriting()) - return; + const CPDF_CIDFont* pCIDFont = pFont->AsCIDFont(); + if (!IsVertWritingCIDFont(pCIDFont)) + return info; - uint16_t CID = pFont->AsCIDFont()->CIDFromCharCode(pInfo->m_CharCode); - pInfo->m_Origin = CFX_PointF(0, pInfo->m_Origin.x); + uint16_t cid = pCIDFont->CIDFromCharCode(info.m_CharCode); + info.m_Origin = CFX_PointF(0, info.m_Origin.x); - short vx; - short vy; - pFont->AsCIDFont()->GetVertOrigin(CID, vx, vy); - + CFX_Point16 vertical_origin = pCIDFont->GetVertOrigin(cid); float fontsize = GetFontSize(); - pInfo->m_Origin.x -= fontsize * vx / 1000; - pInfo->m_Origin.y -= fontsize * vy / 1000; + info.m_Origin.x -= fontsize * vertical_origin.x / 1000; + info.m_Origin.y -= fontsize * vertical_origin.y / 1000; + return info; } size_t CPDF_TextObject::CountChars() const { @@ -67,38 +74,28 @@ return count; } -void CPDF_TextObject::GetCharInfo(size_t index, - uint32_t* charcode, - float* kerning) const { +uint32_t CPDF_TextObject::GetCharCode(size_t index) const { size_t count = 0; - for (size_t i = 0; i < m_CharCodes.size(); ++i) { - if (m_CharCodes[i] == CPDF_Font::kInvalidCharCode) + for (uint32_t code : m_CharCodes) { + if (code == CPDF_Font::kInvalidCharCode) continue; if (count++ != index) continue; - *charcode = m_CharCodes[i]; - if (i == m_CharCodes.size() - 1 || - m_CharCodes[i + 1] != CPDF_Font::kInvalidCharCode) { - *kerning = 0; - } else { - *kerning = m_CharPos[i]; - } - return; + return code; } + return CPDF_Font::kInvalidCharCode; } -void CPDF_TextObject::GetCharInfo(size_t index, - CPDF_TextObjectItem* pInfo) const { +CPDF_TextObject::Item CPDF_TextObject::GetCharInfo(size_t index) const { size_t count = 0; for (size_t i = 0; i < m_CharCodes.size(); ++i) { uint32_t charcode = m_CharCodes[i]; if (charcode == CPDF_Font::kInvalidCharCode) continue; - if (count++ != index) - continue; - GetItemInfo(i, pInfo); - break; + if (count++ == index) + return GetItemInfo(i); } + return Item(); } int CPDF_TextObject::CountWords() const { @@ -106,9 +103,7 @@ bool bInLatinWord = false; int nWords = 0; for (size_t i = 0, sz = CountChars(); i < sz; ++i) { - uint32_t charcode = CPDF_Font::kInvalidCharCode; - float unused_kerning; - GetCharInfo(i, &charcode, &unused_kerning); + uint32_t charcode = GetCharCode(i); WideString swUnicode = pFont->UnicodeFromCharCode(charcode); uint16_t unicode = 0; @@ -133,9 +128,7 @@ int nWords = 0; bool bInLatinWord = false; for (size_t i = 0, sz = CountChars(); i < sz; ++i) { - uint32_t charcode = CPDF_Font::kInvalidCharCode; - float unused_kerning; - GetCharInfo(i, &charcode, &unused_kerning); + uint32_t charcode = GetCharCode(i); WideString swUnicode = pFont->UnicodeFromCharCode(charcode); uint16_t unicode = 0; @@ -155,7 +148,7 @@ } std::unique_ptr<CPDF_TextObject> CPDF_TextObject::Clone() const { - auto obj = pdfium::MakeUnique<CPDF_TextObject>(); + auto obj = std::make_unique<CPDF_TextObject>(); obj->CopyData(this); obj->m_CharCodes = m_CharCodes; obj->m_CharPos = m_CharPos; @@ -164,19 +157,11 @@ } CPDF_PageObject::Type CPDF_TextObject::GetType() const { - return TEXT; + return Type::kText; } void CPDF_TextObject::Transform(const CFX_Matrix& matrix) { - CFX_Matrix text_matrix = GetTextMatrix() * matrix; - - float* pTextMatrix = m_TextState.GetMutableMatrix(); - pTextMatrix[0] = text_matrix.a; - pTextMatrix[1] = text_matrix.c; - pTextMatrix[2] = text_matrix.b; - pTextMatrix[3] = text_matrix.d; - m_Pos = CFX_PointF(text_matrix.e, text_matrix.f); - CalcPositionData(0); + SetTextMatrix(GetTextMatrix() * matrix); SetDirty(true); } @@ -193,21 +178,33 @@ } CFX_Matrix CPDF_TextObject::GetTextMatrix() const { - const float* pTextMatrix = m_TextState.GetMatrix(); + pdfium::span<const float> pTextMatrix = m_TextState.GetMatrix(); return CFX_Matrix(pTextMatrix[0], pTextMatrix[2], pTextMatrix[1], pTextMatrix[3], m_Pos.x, m_Pos.y); } +void CPDF_TextObject::SetTextMatrix(const CFX_Matrix& matrix) { + pdfium::span<float> pTextMatrix = m_TextState.GetMutableMatrix(); + pTextMatrix[0] = matrix.a; + pTextMatrix[1] = matrix.c; + pTextMatrix[2] = matrix.b; + pTextMatrix[3] = matrix.d; + m_Pos = CFX_PointF(matrix.e, matrix.f); + CalcPositionDataInternal(GetFont()); +} + void CPDF_TextObject::SetSegments(const ByteString* pStrs, const std::vector<float>& kernings, size_t nSegs) { + CHECK(nSegs); m_CharCodes.clear(); m_CharPos.clear(); RetainPtr<CPDF_Font> pFont = GetFont(); - int nChars = 0; + size_t nChars = nSegs - 1; for (size_t i = 0; i < nSegs; ++i) nChars += pFont->CountChar(pStrs[i].AsStringView()); - nChars += nSegs - 1; + + CHECK(nChars); m_CharCodes.resize(nChars); m_CharPos.resize(nChars - 1); size_t index = 0; @@ -215,7 +212,7 @@ ByteStringView segment = pStrs[i].AsStringView(); size_t offset = 0; while (offset < segment.GetLength()) { - ASSERT(index < m_CharCodes.size()); + DCHECK(index < m_CharCodes.size()); m_CharCodes[index++] = pFont->GetNextChar(segment, &offset); } if (i != nSegs - 1) { @@ -227,22 +224,19 @@ void CPDF_TextObject::SetText(const ByteString& str) { SetSegments(&str, std::vector<float>(), 1); - RecalcPositionData(); + CalcPositionDataInternal(GetFont()); SetDirty(true); } float CPDF_TextObject::GetCharWidth(uint32_t charcode) const { - float fontsize = GetFontSize() / 1000; + const float fontsize = GetFontSize() / 1000; RetainPtr<CPDF_Font> pFont = GetFont(); - bool bVertWriting = false; - CPDF_CIDFont* pCIDFont = pFont->AsCIDFont(); - if (pCIDFont) - bVertWriting = pCIDFont->IsVertWriting(); - if (!bVertWriting) + const CPDF_CIDFont* pCIDFont = pFont->AsCIDFont(); + if (!IsVertWritingCIDFont(pCIDFont)) return pFont->GetCharWidthF(charcode) * fontsize; - uint16_t CID = pCIDFont->CIDFromCharCode(charcode); - return pCIDFont->GetVertWidth(CID) * fontsize; + uint16_t cid = pCIDFont->CIDFromCharCode(charcode); + return pCIDFont->GetVertWidth(cid) * fontsize; } RetainPtr<CPDF_Font> CPDF_TextObject::GetFont() const { @@ -257,21 +251,32 @@ return m_TextState.GetTextMode(); } -CFX_PointF CPDF_TextObject::CalcPositionData(float horz_scale) { - float curpos = 0; - float min_x = 10000 * 1.0f; - float max_x = -10000 * 1.0f; - float min_y = 10000 * 1.0f; - float max_y = -10000 * 1.0f; - RetainPtr<CPDF_Font> pFont = GetFont(); - bool bVertWriting = false; - CPDF_CIDFont* pCIDFont = pFont->AsCIDFont(); - if (pCIDFont) - bVertWriting = pCIDFont->IsVertWriting(); +void CPDF_TextObject::SetTextRenderMode(TextRenderingMode mode) { + m_TextState.SetTextMode(mode); + SetDirty(true); +} - float fontsize = GetFontSize(); +CFX_PointF CPDF_TextObject::CalcPositionData(float horz_scale) { + RetainPtr<CPDF_Font> pFont = GetFont(); + const float curpos = CalcPositionDataInternal(pFont); + if (IsVertWritingCIDFont(pFont->AsCIDFont())) + return {0, curpos}; + return {curpos * horz_scale, 0}; +} + +float CPDF_TextObject::CalcPositionDataInternal( + const RetainPtr<CPDF_Font>& pFont) { + float curpos = 0; + float min_x = 10000.0f; + float max_x = -10000.0f; + float min_y = 10000.0f; + float max_y = -10000.0f; + const CPDF_CIDFont* pCIDFont = pFont->AsCIDFont(); + const bool bVertWriting = IsVertWritingCIDFont(pCIDFont); + const float fontsize = GetFontSize(); + for (size_t i = 0; i < m_CharCodes.size(); ++i) { - uint32_t charcode = m_CharCodes[i]; + const uint32_t charcode = m_CharCodes[i]; if (i > 0) { if (charcode == CPDF_Font::kInvalidCharCode) { curpos -= (m_CharPos[i - 1] * fontsize) / 1000; @@ -282,34 +287,29 @@ FX_RECT char_rect = pFont->GetCharBBox(charcode); float charwidth; - if (!bVertWriting) { - min_y = std::min( - min_y, static_cast<float>(std::min(char_rect.top, char_rect.bottom))); - max_y = std::max( - max_y, static_cast<float>(std::max(char_rect.top, char_rect.bottom))); - float char_left = curpos + char_rect.left * fontsize / 1000; - float char_right = curpos + char_rect.right * fontsize / 1000; - min_x = std::min(min_x, std::min(char_left, char_right)); - max_x = std::max(max_x, std::max(char_left, char_right)); - charwidth = pFont->GetCharWidthF(charcode) * fontsize / 1000; - } else { - uint16_t CID = pCIDFont->CIDFromCharCode(charcode); - short vx; - short vy; - pCIDFont->GetVertOrigin(CID, vx, vy); - char_rect.left -= vx; - char_rect.right -= vx; - char_rect.top -= vy; - char_rect.bottom -= vy; + if (bVertWriting) { + uint16_t cid = pCIDFont->CIDFromCharCode(charcode); + CFX_Point16 vertical_origin = pCIDFont->GetVertOrigin(cid); + char_rect.Offset(-vertical_origin.x, -vertical_origin.y); min_x = std::min( min_x, static_cast<float>(std::min(char_rect.left, char_rect.right))); max_x = std::max( max_x, static_cast<float>(std::max(char_rect.left, char_rect.right))); - float char_top = curpos + char_rect.top * fontsize / 1000; - float char_bottom = curpos + char_rect.bottom * fontsize / 1000; + const float char_top = curpos + char_rect.top * fontsize / 1000; + const float char_bottom = curpos + char_rect.bottom * fontsize / 1000; min_y = std::min(min_y, std::min(char_top, char_bottom)); max_y = std::max(max_y, std::max(char_top, char_bottom)); - charwidth = pCIDFont->GetVertWidth(CID) * fontsize / 1000; + charwidth = pCIDFont->GetVertWidth(cid) * fontsize / 1000; + } else { + min_y = std::min( + min_y, static_cast<float>(std::min(char_rect.top, char_rect.bottom))); + max_y = std::max( + max_y, static_cast<float>(std::max(char_rect.top, char_rect.bottom))); + const float char_left = curpos + char_rect.left * fontsize / 1000; + const float char_right = curpos + char_rect.right * fontsize / 1000; + min_x = std::min(min_x, std::min(char_left, char_right)); + max_x = std::max(max_x, std::max(char_left, char_right)); + charwidth = pFont->GetCharWidthF(charcode) * fontsize / 1000; } curpos += charwidth; if (charcode == ' ' && (!pCIDFont || pCIDFont->GetCharSize(' ') == 1)) @@ -318,31 +318,23 @@ curpos += m_TextState.GetCharSpace(); } - CFX_PointF ret; if (bVertWriting) { - ret.y = curpos; min_x = min_x * fontsize / 1000; max_x = max_x * fontsize / 1000; } else { - ret.x = curpos * horz_scale; min_y = min_y * fontsize / 1000; max_y = max_y * fontsize / 1000; } - SetRect( - GetTextMatrix().TransformRect(CFX_FloatRect(min_x, min_y, max_x, max_y))); - if (!TextRenderingModeIsStrokeMode(m_TextState.GetTextMode())) - return ret; + SetOriginalRect(CFX_FloatRect(min_x, min_y, max_x, max_y)); + CFX_FloatRect rect = GetTextMatrix().TransformRect(GetOriginalRect()); + if (TextRenderingModeIsStrokeMode(m_TextState.GetTextMode())) { + // TODO(crbug.com/pdfium/1840): Does the original rect need a similar + // adjustment? + const float half_width = m_GraphState.GetLineWidth() / 2; + rect.Inflate(half_width, half_width); + } + SetRect(rect); - float half_width = m_GraphState.GetLineWidth() / 2; - m_Rect.left -= half_width; - m_Rect.right += half_width; - m_Rect.top += half_width; - m_Rect.bottom -= half_width; - - return ret; -} - -void CPDF_TextObject::RecalcPositionData() { - CalcPositionData(1); + return curpos; }
diff --git a/core/fpdfapi/page/cpdf_textobject.h b/core/fpdfapi/page/cpdf_textobject.h index ad9918e..4a936bc 100644 --- a/core/fpdfapi/page/cpdf_textobject.h +++ b/core/fpdfapi/page/cpdf_textobject.h
@@ -1,4 +1,4 @@ -// Copyright 2016 PDFium Authors. All rights reserved. +// Copyright 2016 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -7,30 +7,33 @@ #ifndef CORE_FPDFAPI_PAGE_CPDF_TEXTOBJECT_H_ #define CORE_FPDFAPI_PAGE_CPDF_TEXTOBJECT_H_ +#include <stddef.h> +#include <stdint.h> + #include <memory> #include <vector> #include "core/fpdfapi/page/cpdf_pageobject.h" +#include "core/fxcrt/fx_coordinates.h" #include "core/fxcrt/fx_string.h" -#include "core/fxcrt/fx_system.h" #include "core/fxcrt/retain_ptr.h" -class CPDF_TextObjectItem { - public: - CPDF_TextObjectItem(); - ~CPDF_TextObjectItem(); - - uint32_t m_CharCode; - CFX_PointF m_Origin; -}; - class CPDF_TextObject final : public CPDF_PageObject { public: + struct Item { + Item(); + Item(const Item& that); + ~Item(); + + uint32_t m_CharCode = 0; + CFX_PointF m_Origin; + }; + explicit CPDF_TextObject(int32_t content_stream); CPDF_TextObject(); ~CPDF_TextObject() override; - // CPDF_PageObject + // CPDF_PageObject: Type GetType() const override; void Transform(const CFX_Matrix& matrix) override; bool IsText() const override; @@ -40,11 +43,11 @@ std::unique_ptr<CPDF_TextObject> Clone() const; size_t CountItems() const; - void GetItemInfo(size_t index, CPDF_TextObjectItem* pInfo) const; + Item GetItemInfo(size_t index) const; size_t CountChars() const; - void GetCharInfo(size_t index, uint32_t* charcode, float* kerning) const; - void GetCharInfo(size_t index, CPDF_TextObjectItem* pInfo) const; + uint32_t GetCharCode(size_t index) const; + Item GetCharInfo(size_t index) const; float GetCharWidth(uint32_t charcode) const; int CountWords() const; WideString GetWordString(int nWordIndex) const; @@ -56,21 +59,25 @@ float GetFontSize() const; TextRenderingMode GetTextRenderMode() const; + void SetTextRenderMode(TextRenderingMode mode); void SetText(const ByteString& str); void SetPosition(const CFX_PointF& pos) { m_Pos = pos; } - void RecalcPositionData(); - const std::vector<uint32_t>& GetCharCodes() const { return m_CharCodes; } const std::vector<float>& GetCharPositions() const { return m_CharPos; } + // Caller is expected to call SetDirty(true) when done changing the object. + void SetTextMatrix(const CFX_Matrix& matrix); + void SetSegments(const ByteString* pStrs, const std::vector<float>& kernings, size_t nSegs); CFX_PointF CalcPositionData(float horz_scale); private: + float CalcPositionDataInternal(const RetainPtr<CPDF_Font>& pFont); + CFX_PointF m_Pos; std::vector<uint32_t> m_CharCodes; std::vector<float> m_CharPos;
diff --git a/core/fpdfapi/page/cpdf_textstate.cpp b/core/fpdfapi/page/cpdf_textstate.cpp index b8019d5..6e48b87 100644 --- a/core/fpdfapi/page/cpdf_textstate.cpp +++ b/core/fpdfapi/page/cpdf_textstate.cpp
@@ -1,4 +1,4 @@ -// Copyright 2016 PDFium Authors. All rights reserved. +// Copyright 2016 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -6,9 +6,12 @@ #include "core/fpdfapi/page/cpdf_textstate.h" +#include <math.h> + +#include <utility> + #include "core/fpdfapi/font/cpdf_font.h" #include "core/fpdfapi/page/cpdf_docpagedata.h" -#include "core/fpdfapi/parser/cpdf_document.h" CPDF_TextState::CPDF_TextState() = default; @@ -22,8 +25,8 @@ return m_Ref.GetObject()->m_pFont; } -void CPDF_TextState::SetFont(const RetainPtr<CPDF_Font>& pFont) { - m_Ref.GetPrivateCopy()->SetFont(pFont); +void CPDF_TextState::SetFont(RetainPtr<CPDF_Font> pFont) { + m_Ref.GetPrivateCopy()->SetFont(std::move(pFont)); } float CPDF_TextState::GetFontSize() const { @@ -34,11 +37,11 @@ m_Ref.GetPrivateCopy()->m_FontSize = size; } -const float* CPDF_TextState::GetMatrix() const { +pdfium::span<const float> CPDF_TextState::GetMatrix() const { return m_Ref.GetObject()->m_Matrix; } -float* CPDF_TextState::GetMutableMatrix() { +pdfium::span<float> CPDF_TextState::GetMutableMatrix() { return m_Ref.GetPrivateCopy()->m_Matrix; } @@ -70,26 +73,15 @@ m_Ref.GetPrivateCopy()->m_TextMode = mode; } -const float* CPDF_TextState::GetCTM() const { +pdfium::span<const float> CPDF_TextState::GetCTM() const { return m_Ref.GetObject()->m_CTM; } -float* CPDF_TextState::GetMutableCTM() { +pdfium::span<float> CPDF_TextState::GetMutableCTM() { return m_Ref.GetPrivateCopy()->m_CTM; } -CPDF_TextState::TextData::TextData() - : m_pFont(nullptr), - m_pDocument(nullptr), - m_FontSize(1.0f), - m_CharSpace(0), - m_WordSpace(0), - m_TextMode(TextRenderingMode::MODE_FILL) { - m_Matrix[0] = m_Matrix[3] = 1.0f; - m_Matrix[1] = m_Matrix[2] = 0; - m_CTM[0] = m_CTM[3] = 1.0f; - m_CTM[1] = m_CTM[2] = 0; -} +CPDF_TextState::TextData::TextData() = default; CPDF_TextState::TextData::TextData(const TextData& that) : m_pFont(that.m_pFont), @@ -105,8 +97,8 @@ m_CTM[i] = that.m_CTM[i]; if (m_pDocument && m_pFont) { - auto* pPageData = CPDF_DocPageData::FromDocument(m_pDocument.Get()); - m_pFont = pPageData->GetFont(m_pFont->GetFontDict()); + auto* pPageData = CPDF_DocPageData::FromDocument(m_pDocument); + m_pFont = pPageData->GetFont(m_pFont->GetMutableFontDict()); } } @@ -116,9 +108,9 @@ return pdfium::MakeRetain<CPDF_TextState::TextData>(*this); } -void CPDF_TextState::TextData::SetFont(const RetainPtr<CPDF_Font>& pFont) { +void CPDF_TextState::TextData::SetFont(RetainPtr<CPDF_Font> pFont) { m_pDocument = pFont ? pFont->GetDocument() : nullptr; - m_pFont = pFont; + m_pFont = std::move(pFont); } float CPDF_TextState::TextData::GetFontSizeH() const {
diff --git a/core/fpdfapi/page/cpdf_textstate.h b/core/fpdfapi/page/cpdf_textstate.h index 5cc0c1d..932d5a7 100644 --- a/core/fpdfapi/page/cpdf_textstate.h +++ b/core/fpdfapi/page/cpdf_textstate.h
@@ -1,4 +1,4 @@ -// Copyright 2016 PDFium Authors. All rights reserved. +// Copyright 2016 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -10,6 +10,7 @@ #include "core/fxcrt/retain_ptr.h" #include "core/fxcrt/shared_copy_on_write.h" #include "core/fxcrt/unowned_ptr.h" +#include "third_party/base/span.h" class CPDF_Document; class CPDF_Font; @@ -36,13 +37,13 @@ void Emplace(); RetainPtr<CPDF_Font> GetFont() const; - void SetFont(const RetainPtr<CPDF_Font>& pFont); + void SetFont(RetainPtr<CPDF_Font> pFont); float GetFontSize() const; void SetFontSize(float size); - const float* GetMatrix() const; - float* GetMutableMatrix(); + pdfium::span<const float> GetMatrix() const; + pdfium::span<float> GetMutableMatrix(); float GetCharSpace() const; void SetCharSpace(float sp); @@ -55,29 +56,28 @@ TextRenderingMode GetTextMode() const; void SetTextMode(TextRenderingMode mode); - const float* GetCTM() const; - float* GetMutableCTM(); + pdfium::span<const float> GetCTM() const; + pdfium::span<float> GetMutableCTM(); private: class TextData final : public Retainable { public: - template <typename T, typename... Args> - friend RetainPtr<T> pdfium::MakeRetain(Args&&... args); + CONSTRUCT_VIA_MAKE_RETAIN; RetainPtr<TextData> Clone() const; - void SetFont(const RetainPtr<CPDF_Font>& pFont); + void SetFont(RetainPtr<CPDF_Font> pFont); float GetFontSizeV() const; float GetFontSizeH() const; RetainPtr<CPDF_Font> m_pFont; - UnownedPtr<CPDF_Document> m_pDocument; - float m_FontSize; - float m_CharSpace; - float m_WordSpace; - TextRenderingMode m_TextMode; - float m_Matrix[4]; - float m_CTM[4]; + UnownedPtr<const CPDF_Document> m_pDocument; + float m_FontSize = 1.0f; + float m_CharSpace = 0.0f; + float m_WordSpace = 0.0f; + TextRenderingMode m_TextMode = TextRenderingMode::MODE_FILL; + float m_Matrix[4] = {1.0f, 0.0f, 0.0f, 1.0f}; + float m_CTM[4] = {1.0f, 0.0f, 0.0f, 1.0f}; private: TextData();
diff --git a/core/fpdfapi/page/cpdf_tilingpattern.cpp b/core/fpdfapi/page/cpdf_tilingpattern.cpp index 46a59db..d7b2fd3 100644 --- a/core/fpdfapi/page/cpdf_tilingpattern.cpp +++ b/core/fpdfapi/page/cpdf_tilingpattern.cpp
@@ -1,4 +1,4 @@ -// Copyright 2016 PDFium Authors. All rights reserved. +// Copyright 2016 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -6,19 +6,23 @@ #include "core/fpdfapi/page/cpdf_tilingpattern.h" +#include <math.h> + +#include <utility> + #include "core/fpdfapi/page/cpdf_allstates.h" #include "core/fpdfapi/page/cpdf_form.h" #include "core/fpdfapi/page/cpdf_pageobject.h" #include "core/fpdfapi/parser/cpdf_dictionary.h" #include "core/fpdfapi/parser/cpdf_object.h" #include "core/fpdfapi/parser/cpdf_stream.h" -#include "third_party/base/ptr_util.h" +#include "third_party/base/check.h" CPDF_TilingPattern::CPDF_TilingPattern(CPDF_Document* pDoc, - CPDF_Object* pPatternObj, + RetainPtr<CPDF_Object> pPatternObj, const CFX_Matrix& parentMatrix) - : CPDF_Pattern(pDoc, pPatternObj, parentMatrix) { - ASSERT(document()); + : CPDF_Pattern(pDoc, std::move(pPatternObj), parentMatrix) { + DCHECK(document()); m_bColored = pattern_obj()->GetDict()->GetIntegerFor("PaintType") == 1; SetPatternToFormMatrix(); } @@ -30,17 +34,18 @@ } std::unique_ptr<CPDF_Form> CPDF_TilingPattern::Load(CPDF_PageObject* pPageObj) { - const CPDF_Dictionary* pDict = pattern_obj()->GetDict(); + RetainPtr<const CPDF_Dictionary> pDict = pattern_obj()->GetDict(); m_bColored = pDict->GetIntegerFor("PaintType") == 1; - m_XStep = static_cast<float>(fabs(pDict->GetNumberFor("XStep"))); - m_YStep = static_cast<float>(fabs(pDict->GetNumberFor("YStep"))); + m_XStep = fabsf(pDict->GetFloatFor("XStep")); + m_YStep = fabsf(pDict->GetFloatFor("YStep")); - CPDF_Stream* pStream = pattern_obj()->AsStream(); + RetainPtr<CPDF_Stream> pStream = ToStream(pattern_obj()); if (!pStream) return nullptr; const CFX_Matrix& matrix = parent_matrix(); - auto form = pdfium::MakeUnique<CPDF_Form>(document(), nullptr, pStream); + auto form = + std::make_unique<CPDF_Form>(document(), nullptr, std::move(pStream)); CPDF_AllStates allStates; allStates.m_ColorState.Emplace();
diff --git a/core/fpdfapi/page/cpdf_tilingpattern.h b/core/fpdfapi/page/cpdf_tilingpattern.h index 134da8e..519e457 100644 --- a/core/fpdfapi/page/cpdf_tilingpattern.h +++ b/core/fpdfapi/page/cpdf_tilingpattern.h
@@ -1,4 +1,4 @@ -// Copyright 2016 PDFium Authors. All rights reserved. +// Copyright 2016 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -11,7 +11,7 @@ #include "core/fpdfapi/page/cpdf_pattern.h" #include "core/fxcrt/fx_coordinates.h" -#include "core/fxcrt/fx_system.h" +#include "core/fxcrt/retain_ptr.h" class CPDF_Document; class CPDF_Form; @@ -20,9 +20,7 @@ class CPDF_TilingPattern final : public CPDF_Pattern { public: - template <typename T, typename... Args> - friend RetainPtr<T> pdfium::MakeRetain(Args&&... args); - + CONSTRUCT_VIA_MAKE_RETAIN; ~CPDF_TilingPattern() override; // CPDF_Pattern: @@ -37,15 +35,15 @@ private: CPDF_TilingPattern(CPDF_Document* pDoc, - CPDF_Object* pPatternObj, + RetainPtr<CPDF_Object> pPatternObj, const CFX_Matrix& parentMatrix); CPDF_TilingPattern(const CPDF_TilingPattern&) = delete; CPDF_TilingPattern& operator=(const CPDF_TilingPattern&) = delete; bool m_bColored; CFX_FloatRect m_BBox; - float m_XStep; - float m_YStep; + float m_XStep = 0.0f; + float m_YStep = 0.0f; }; #endif // CORE_FPDFAPI_PAGE_CPDF_TILINGPATTERN_H_
diff --git a/core/fpdfapi/page/cpdf_transferfunc.cpp b/core/fpdfapi/page/cpdf_transferfunc.cpp index 9e3092b..f7aa5e5 100644 --- a/core/fpdfapi/page/cpdf_transferfunc.cpp +++ b/core/fpdfapi/page/cpdf_transferfunc.cpp
@@ -1,4 +1,4 @@ -// Copyright 2016 PDFium Authors. All rights reserved. +// Copyright 2016 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -6,39 +6,41 @@ #include "core/fpdfapi/page/cpdf_transferfunc.h" +#include <stdint.h> + #include <utility> #include "core/fpdfapi/page/cpdf_transferfuncdib.h" #include "core/fpdfapi/parser/cpdf_document.h" +#include "core/fxcrt/fixed_uninit_data_vector.h" #include "core/fxge/dib/cfx_dibbase.h" +#include "third_party/base/check_op.h" -CPDF_TransferFunc::CPDF_TransferFunc(CPDF_Document* pDoc, - bool bIdentify, - std::vector<uint8_t> samples_r, - std::vector<uint8_t> samples_g, - std::vector<uint8_t> samples_b) - : m_pPDFDoc(pDoc), - m_bIdentity(bIdentify), +CPDF_TransferFunc::CPDF_TransferFunc(bool bIdentify, + FixedUninitDataVector<uint8_t> samples_r, + FixedUninitDataVector<uint8_t> samples_g, + FixedUninitDataVector<uint8_t> samples_b) + : m_bIdentity(bIdentify), m_SamplesR(std::move(samples_r)), m_SamplesG(std::move(samples_g)), m_SamplesB(std::move(samples_b)) { - ASSERT(m_SamplesR.size() == kChannelSampleSize); - ASSERT(m_SamplesG.size() == kChannelSampleSize); - ASSERT(m_SamplesB.size() == kChannelSampleSize); + DCHECK_EQ(m_SamplesR.size(), kChannelSampleSize); + DCHECK_EQ(m_SamplesG.size(), kChannelSampleSize); + DCHECK_EQ(m_SamplesB.size(), kChannelSampleSize); } CPDF_TransferFunc::~CPDF_TransferFunc() = default; FX_COLORREF CPDF_TransferFunc::TranslateColor(FX_COLORREF colorref) const { - return FXSYS_BGR(m_SamplesB[FXSYS_GetBValue(colorref)], - m_SamplesG[FXSYS_GetGValue(colorref)], - m_SamplesR[FXSYS_GetRValue(colorref)]); + return FXSYS_BGR(m_SamplesB.span()[FXSYS_GetBValue(colorref)], + m_SamplesG.span()[FXSYS_GetGValue(colorref)], + m_SamplesR.span()[FXSYS_GetRValue(colorref)]); } RetainPtr<CFX_DIBBase> CPDF_TransferFunc::TranslateImage( - const RetainPtr<CFX_DIBBase>& pSrc) { - RetainPtr<CPDF_TransferFunc> pHolder(this); - return pdfium::MakeRetain<CPDF_TransferFuncDIB>(pSrc, pHolder); + RetainPtr<CFX_DIBBase> pSrc) { + return pdfium::MakeRetain<CPDF_TransferFuncDIB>(std::move(pSrc), + pdfium::WrapRetain(this)); } pdfium::span<const uint8_t> CPDF_TransferFunc::GetSamplesR() const {
diff --git a/core/fpdfapi/page/cpdf_transferfunc.h b/core/fpdfapi/page/cpdf_transferfunc.h index b2d997e..d168930 100644 --- a/core/fpdfapi/page/cpdf_transferfunc.h +++ b/core/fpdfapi/page/cpdf_transferfunc.h
@@ -1,4 +1,4 @@ -// Copyright 2016 PDFium Authors. All rights reserved. +// Copyright 2016 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -7,28 +7,24 @@ #ifndef CORE_FPDFAPI_PAGE_CPDF_TRANSFERFUNC_H_ #define CORE_FPDFAPI_PAGE_CPDF_TRANSFERFUNC_H_ -#include <vector> +#include <stdint.h> +#include "core/fxcrt/fixed_uninit_data_vector.h" #include "core/fxcrt/observed_ptr.h" #include "core/fxcrt/retain_ptr.h" -#include "core/fxcrt/unowned_ptr.h" -#include "core/fxge/fx_dib.h" +#include "core/fxge/dib/fx_dib.h" #include "third_party/base/span.h" -class CPDF_Document; class CFX_DIBBase; class CPDF_TransferFunc final : public Retainable, public Observable { public: - template <typename T, typename... Args> - friend RetainPtr<T> pdfium::MakeRetain(Args&&... args); + CONSTRUCT_VIA_MAKE_RETAIN; static constexpr size_t kChannelSampleSize = 256; FX_COLORREF TranslateColor(FX_COLORREF colorref) const; - RetainPtr<CFX_DIBBase> TranslateImage(const RetainPtr<CFX_DIBBase>& pSrc); - - const CPDF_Document* GetDocument() const { return m_pPDFDoc.Get(); } + RetainPtr<CFX_DIBBase> TranslateImage(RetainPtr<CFX_DIBBase> pSrc); // Spans are |kChannelSampleSize| in size. pdfium::span<const uint8_t> GetSamplesR() const; @@ -38,18 +34,16 @@ bool GetIdentity() const { return m_bIdentity; } private: - CPDF_TransferFunc(CPDF_Document* pDoc, - bool bIdentify, - std::vector<uint8_t> samples_r, - std::vector<uint8_t> samples_g, - std::vector<uint8_t> samples_b); + CPDF_TransferFunc(bool bIdentify, + FixedUninitDataVector<uint8_t> samples_r, + FixedUninitDataVector<uint8_t> samples_g, + FixedUninitDataVector<uint8_t> samples_b); ~CPDF_TransferFunc() override; - UnownedPtr<CPDF_Document> const m_pPDFDoc; const bool m_bIdentity; - const std::vector<uint8_t> m_SamplesR; - const std::vector<uint8_t> m_SamplesG; - const std::vector<uint8_t> m_SamplesB; + const FixedUninitDataVector<uint8_t> m_SamplesR; + const FixedUninitDataVector<uint8_t> m_SamplesG; + const FixedUninitDataVector<uint8_t> m_SamplesB; }; #endif // CORE_FPDFAPI_PAGE_CPDF_TRANSFERFUNC_H_
diff --git a/core/fpdfapi/page/cpdf_transferfuncdib.cpp b/core/fpdfapi/page/cpdf_transferfuncdib.cpp index f985616..24e4007 100644 --- a/core/fpdfapi/page/cpdf_transferfuncdib.cpp +++ b/core/fpdfapi/page/cpdf_transferfuncdib.cpp
@@ -1,4 +1,4 @@ -// Copyright 2016 PDFium Authors. All rights reserved. +// Copyright 2016 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -6,50 +6,48 @@ #include "core/fpdfapi/page/cpdf_transferfuncdib.h" -#include <vector> +#include <utility> #include "build/build_config.h" #include "core/fpdfapi/page/cpdf_transferfunc.h" #include "core/fpdfapi/parser/cpdf_dictionary.h" -#include "third_party/base/compiler_specific.h" +#include "core/fxge/calculate_pitch.h" +#include "third_party/base/check.h" CPDF_TransferFuncDIB::CPDF_TransferFuncDIB( - const RetainPtr<CFX_DIBBase>& pSrc, - const RetainPtr<CPDF_TransferFunc>& pTransferFunc) - : m_pSrc(pSrc), - m_pTransferFunc(pTransferFunc), - m_RampR(pTransferFunc->GetSamplesR()), - m_RampG(pTransferFunc->GetSamplesG()), - m_RampB(pTransferFunc->GetSamplesB()) { - m_Width = pSrc->GetWidth(); - m_Height = pSrc->GetHeight(); - FXDIB_Format format = GetDestFormat(); - m_bpp = GetBppFromFormat(format); - m_AlphaFlag = GetAlphaFlagFromFormat(format); - m_Pitch = (m_Width * m_bpp + 31) / 32 * 4; - m_pPalette.reset(); + RetainPtr<CFX_DIBBase> pSrc, + RetainPtr<CPDF_TransferFunc> pTransferFunc) + : m_pSrc(std::move(pSrc)), + m_pTransferFunc(std::move(pTransferFunc)), + m_RampR(m_pTransferFunc->GetSamplesR()), + m_RampG(m_pTransferFunc->GetSamplesG()), + m_RampB(m_pTransferFunc->GetSamplesB()) { + m_Width = m_pSrc->GetWidth(); + m_Height = m_pSrc->GetHeight(); + m_Format = GetDestFormat(); + m_Pitch = fxge::CalculatePitch32OrDie(GetBppFromFormat(m_Format), m_Width); m_Scanline.resize(m_Pitch); + DCHECK(m_palette.empty()); } CPDF_TransferFuncDIB::~CPDF_TransferFuncDIB() = default; FXDIB_Format CPDF_TransferFuncDIB::GetDestFormat() const { - if (m_pSrc->IsAlphaMask()) - return FXDIB_8bppMask; + if (m_pSrc->IsMaskFormat()) + return FXDIB_Format::k8bppMask; -#if defined(OS_MACOSX) - return m_pSrc->HasAlpha() ? FXDIB_Argb : FXDIB_Rgb32; -#else - return m_pSrc->HasAlpha() ? FXDIB_Argb : FXDIB_Rgb; -#endif + if (m_pSrc->IsAlphaFormat()) + return FXDIB_Format::kArgb; + + return CFX_DIBBase::kPlatformRGBFormat; } void CPDF_TransferFuncDIB::TranslateScanline( - const uint8_t* src_buf, - std::vector<uint8_t>* dest_buf) const { + pdfium::span<const uint8_t> src_span) const { + const uint8_t* src_buf = src_span.data(); bool bSkip = false; switch (m_pSrc->GetFormat()) { - case FXDIB_1bppRgb: { + case FXDIB_Format::k1bppRgb: { int r0 = m_RampR[0]; int g0 = m_RampG[0]; int b0 = m_RampB[0]; @@ -59,84 +57,84 @@ int index = 0; for (int i = 0; i < m_Width; i++) { if (src_buf[i / 8] & (1 << (7 - i % 8))) { - (*dest_buf)[index++] = b1; - (*dest_buf)[index++] = g1; - (*dest_buf)[index++] = r1; + m_Scanline[index++] = b1; + m_Scanline[index++] = g1; + m_Scanline[index++] = r1; } else { - (*dest_buf)[index++] = b0; - (*dest_buf)[index++] = g0; - (*dest_buf)[index++] = r0; + m_Scanline[index++] = b0; + m_Scanline[index++] = g0; + m_Scanline[index++] = r0; } -#if defined(OS_MACOSX) +#if BUILDFLAG(IS_APPLE) index++; #endif } break; } - case FXDIB_1bppMask: { + case FXDIB_Format::k1bppMask: { int m0 = m_RampR[0]; int m1 = m_RampR[255]; int index = 0; for (int i = 0; i < m_Width; i++) { if (src_buf[i / 8] & (1 << (7 - i % 8))) - (*dest_buf)[index++] = m1; + m_Scanline[index++] = m1; else - (*dest_buf)[index++] = m0; + m_Scanline[index++] = m0; } break; } - case FXDIB_8bppRgb: { - FX_ARGB* pPal = m_pSrc->GetPalette(); + case FXDIB_Format::k8bppRgb: { + pdfium::span<const uint32_t> src_palette = m_pSrc->GetPaletteSpan(); int index = 0; for (int i = 0; i < m_Width; i++) { - if (pPal) { - FX_ARGB src_argb = pPal[*src_buf]; - (*dest_buf)[index++] = m_RampB[FXARGB_R(src_argb)]; - (*dest_buf)[index++] = m_RampG[FXARGB_G(src_argb)]; - (*dest_buf)[index++] = m_RampR[FXARGB_B(src_argb)]; + if (m_pSrc->HasPalette()) { + FX_ARGB src_argb = src_palette[*src_buf]; + m_Scanline[index++] = m_RampB[FXARGB_R(src_argb)]; + m_Scanline[index++] = m_RampG[FXARGB_G(src_argb)]; + m_Scanline[index++] = m_RampR[FXARGB_B(src_argb)]; } else { uint32_t src_byte = *src_buf; - (*dest_buf)[index++] = m_RampB[src_byte]; - (*dest_buf)[index++] = m_RampG[src_byte]; - (*dest_buf)[index++] = m_RampR[src_byte]; + m_Scanline[index++] = m_RampB[src_byte]; + m_Scanline[index++] = m_RampG[src_byte]; + m_Scanline[index++] = m_RampR[src_byte]; } src_buf++; -#if defined(OS_MACOSX) +#if BUILDFLAG(IS_APPLE) index++; #endif } break; } - case FXDIB_8bppMask: { + case FXDIB_Format::k8bppMask: { int index = 0; for (int i = 0; i < m_Width; i++) - (*dest_buf)[index++] = m_RampR[*(src_buf++)]; + m_Scanline[index++] = m_RampR[*(src_buf++)]; break; } - case FXDIB_Rgb: { + case FXDIB_Format::kRgb: { int index = 0; for (int i = 0; i < m_Width; i++) { - (*dest_buf)[index++] = m_RampB[*(src_buf++)]; - (*dest_buf)[index++] = m_RampG[*(src_buf++)]; - (*dest_buf)[index++] = m_RampR[*(src_buf++)]; -#if defined(OS_MACOSX) + m_Scanline[index++] = m_RampB[*(src_buf++)]; + m_Scanline[index++] = m_RampG[*(src_buf++)]; + m_Scanline[index++] = m_RampR[*(src_buf++)]; +#if BUILDFLAG(IS_APPLE) index++; #endif } break; } - case FXDIB_Rgb32: + case FXDIB_Format::kRgb32: bSkip = true; - FALLTHROUGH; - case FXDIB_Argb: { + [[fallthrough]]; + case FXDIB_Format::kArgb: { int index = 0; for (int i = 0; i < m_Width; i++) { - (*dest_buf)[index++] = m_RampB[*(src_buf++)]; - (*dest_buf)[index++] = m_RampG[*(src_buf++)]; - (*dest_buf)[index++] = m_RampR[*(src_buf++)]; + m_Scanline[index++] = m_RampB[*(src_buf++)]; + m_Scanline[index++] = m_RampG[*(src_buf++)]; + m_Scanline[index++] = m_RampR[*(src_buf++)]; if (!bSkip) { - (*dest_buf)[index++] = *src_buf; -#if defined(OS_MACOSX) + m_Scanline[index++] = *src_buf; +#if BUILDFLAG(IS_APPLE) } else { index++; #endif @@ -150,56 +148,7 @@ } } -void CPDF_TransferFuncDIB::TranslateDownSamples(uint8_t* dest_buf, - const uint8_t* src_buf, - int pixels, - int Bpp) const { - if (Bpp == 8) { - for (int i = 0; i < pixels; i++) - *dest_buf++ = m_RampR[*(src_buf++)]; - } else if (Bpp == 24) { - for (int i = 0; i < pixels; i++) { - *dest_buf++ = m_RampB[*(src_buf++)]; - *dest_buf++ = m_RampG[*(src_buf++)]; - *dest_buf++ = m_RampR[*(src_buf++)]; - } - } else { -#if defined(OS_MACOSX) - if (!m_pSrc->HasAlpha()) { - for (int i = 0; i < pixels; i++) { - *dest_buf++ = m_RampB[*(src_buf++)]; - *dest_buf++ = m_RampG[*(src_buf++)]; - *dest_buf++ = m_RampR[*(src_buf++)]; - dest_buf++; - src_buf++; - } - } else { -#endif - for (int i = 0; i < pixels; i++) { - *dest_buf++ = m_RampB[*(src_buf++)]; - *dest_buf++ = m_RampG[*(src_buf++)]; - *dest_buf++ = m_RampR[*(src_buf++)]; - *dest_buf++ = *(src_buf++); - } -#if defined(OS_MACOSX) - } -#endif - } -} - -const uint8_t* CPDF_TransferFuncDIB::GetScanline(int line) const { - TranslateScanline(m_pSrc->GetScanline(line), &m_Scanline); - return m_Scanline.data(); -} - -void CPDF_TransferFuncDIB::DownSampleScanline(int line, - uint8_t* dest_scan, - int dest_bpp, - int dest_width, - bool bFlipX, - int clip_left, - int clip_width) const { - m_pSrc->DownSampleScanline(line, dest_scan, dest_bpp, dest_width, bFlipX, - clip_left, clip_width); - TranslateDownSamples(dest_scan, dest_scan, clip_width, dest_bpp); +pdfium::span<const uint8_t> CPDF_TransferFuncDIB::GetScanline(int line) const { + TranslateScanline(m_pSrc->GetScanline(line)); + return m_Scanline; }
diff --git a/core/fpdfapi/page/cpdf_transferfuncdib.h b/core/fpdfapi/page/cpdf_transferfuncdib.h index c30718a..a034116 100644 --- a/core/fpdfapi/page/cpdf_transferfuncdib.h +++ b/core/fpdfapi/page/cpdf_transferfuncdib.h
@@ -1,4 +1,4 @@ -// Copyright 2016 PDFium Authors. All rights reserved. +// Copyright 2016 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -7,8 +7,9 @@ #ifndef CORE_FPDFAPI_PAGE_CPDF_TRANSFERFUNCDIB_H_ #define CORE_FPDFAPI_PAGE_CPDF_TRANSFERFUNCDIB_H_ -#include <vector> +#include <stdint.h> +#include "core/fxcrt/data_vector.h" #include "core/fxcrt/retain_ptr.h" #include "core/fxge/dib/cfx_dibbase.h" #include "third_party/base/span.h" @@ -17,39 +18,25 @@ class CPDF_TransferFuncDIB final : public CFX_DIBBase { public: - template <typename T, typename... Args> - friend RetainPtr<T> pdfium::MakeRetain(Args&&... args); - - void TranslateScanline(const uint8_t* src_buf, - std::vector<uint8_t>* dest_buf) const; - void TranslateDownSamples(uint8_t* dest_buf, - const uint8_t* src_buf, - int pixels, - int Bpp) const; - - private: - CPDF_TransferFuncDIB(const RetainPtr<CFX_DIBBase>& pSrc, - const RetainPtr<CPDF_TransferFunc>& pTransferFunc); - ~CPDF_TransferFuncDIB() override; + CONSTRUCT_VIA_MAKE_RETAIN; // CFX_DIBBase: - const uint8_t* GetScanline(int line) const override; - void DownSampleScanline(int line, - uint8_t* dest_scan, - int dest_bpp, - int dest_width, - bool bFlipX, - int clip_left, - int clip_width) const override; + pdfium::span<const uint8_t> GetScanline(int line) const override; + private: + CPDF_TransferFuncDIB(RetainPtr<CFX_DIBBase> pSrc, + RetainPtr<CPDF_TransferFunc> pTransferFunc); + ~CPDF_TransferFuncDIB() override; + + void TranslateScanline(pdfium::span<const uint8_t> src_span) const; FXDIB_Format GetDestFormat() const; RetainPtr<CFX_DIBBase> const m_pSrc; - mutable std::vector<uint8_t> m_Scanline; RetainPtr<CPDF_TransferFunc> const m_pTransferFunc; const pdfium::span<const uint8_t> m_RampR; const pdfium::span<const uint8_t> m_RampG; const pdfium::span<const uint8_t> m_RampB; + mutable DataVector<uint8_t> m_Scanline; }; #endif // CORE_FPDFAPI_PAGE_CPDF_TRANSFERFUNCDIB_H_
diff --git a/core/fpdfapi/page/cpdf_transparency.cpp b/core/fpdfapi/page/cpdf_transparency.cpp index f9be541..811160d 100644 --- a/core/fpdfapi/page/cpdf_transparency.cpp +++ b/core/fpdfapi/page/cpdf_transparency.cpp
@@ -1,4 +1,4 @@ -// Copyright 2018 PDFium Authors. All rights reserved. +// Copyright 2018 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -7,3 +7,6 @@ CPDF_Transparency::CPDF_Transparency() = default; CPDF_Transparency::CPDF_Transparency(const CPDF_Transparency& other) = default; + +CPDF_Transparency& CPDF_Transparency::operator=( + const CPDF_Transparency& other) = default;
diff --git a/core/fpdfapi/page/cpdf_transparency.h b/core/fpdfapi/page/cpdf_transparency.h index 6d4972d..a2e0a25 100644 --- a/core/fpdfapi/page/cpdf_transparency.h +++ b/core/fpdfapi/page/cpdf_transparency.h
@@ -1,4 +1,4 @@ -// Copyright 2018 PDFium Authors. All rights reserved. +// Copyright 2018 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -10,6 +10,7 @@ CPDF_Transparency(); CPDF_Transparency(const CPDF_Transparency& other); + CPDF_Transparency& operator=(const CPDF_Transparency& other); bool IsGroup() const { return m_bGroup; } bool IsIsolated() const { return m_bIsolated; }
diff --git a/core/fpdfapi/page/ipdf_page.h b/core/fpdfapi/page/ipdf_page.h index 9b28559..a71106b 100644 --- a/core/fpdfapi/page/ipdf_page.h +++ b/core/fpdfapi/page/ipdf_page.h
@@ -1,4 +1,4 @@ -// Copyright 2018 PDFium Authors. All rights reserved. +// Copyright 2018 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -9,7 +9,7 @@ #include "core/fxcrt/fx_coordinates.h" #include "core/fxcrt/retain_ptr.h" -#include "third_party/base/optional.h" +#include "third_party/abseil-cpp/absl/types/optional.h" class CPDF_Document; class CPDF_Page; @@ -35,12 +35,12 @@ virtual CFX_Matrix GetDisplayMatrix(const FX_RECT& rect, int iRotate) const = 0; - virtual Optional<CFX_PointF> DeviceToPage( + virtual absl::optional<CFX_PointF> DeviceToPage( const FX_RECT& rect, int rotate, const CFX_PointF& device_point) const = 0; - virtual Optional<CFX_PointF> PageToDevice( + virtual absl::optional<CFX_PointF> PageToDevice( const FX_RECT& rect, int rotate, const CFX_PointF& page_point) const = 0;
diff --git a/core/fpdfapi/page/test_with_page_module.cpp b/core/fpdfapi/page/test_with_page_module.cpp new file mode 100644 index 0000000..0515ad9 --- /dev/null +++ b/core/fpdfapi/page/test_with_page_module.cpp
@@ -0,0 +1,15 @@ +// Copyright 2022 The PDFium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "core/fpdfapi/page/test_with_page_module.h" + +#include "core/fpdfapi/page/cpdf_pagemodule.h" + +void TestWithPageModule::SetUp() { + CPDF_PageModule::Create(); +} + +void TestWithPageModule::TearDown() { + CPDF_PageModule::Destroy(); +}
diff --git a/core/fpdfapi/page/test_with_page_module.h b/core/fpdfapi/page/test_with_page_module.h new file mode 100644 index 0000000..0b39b84 --- /dev/null +++ b/core/fpdfapi/page/test_with_page_module.h
@@ -0,0 +1,16 @@ +// Copyright 2022 The PDFium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CORE_FPDFAPI_PAGE_TEST_WITH_PAGE_MODULE_H_ +#define CORE_FPDFAPI_PAGE_TEST_WITH_PAGE_MODULE_H_ + +#include "testing/gtest/include/gtest/gtest.h" + +class TestWithPageModule : public testing::Test { + public: + void SetUp() override; + void TearDown() override; +}; + +#endif // CORE_FPDFAPI_PAGE_TEST_WITH_PAGE_MODULE_H_
diff --git a/core/fpdfapi/parser/Android.bp b/core/fpdfapi/parser/Android.bp index cacb42e..0ad9807 100644 --- a/core/fpdfapi/parser/Android.bp +++ b/core/fpdfapi/parser/Android.bp
@@ -13,11 +13,8 @@ visibility: ["//external/pdfium:__subpackages__"], - header_libs: [ - "libpdfium-constants", - ], - static_libs: [ + "libpdfium-constants", "libpdfium-fdrm", "libpdfium-fxcodec", "libpdfium-fxcrt",
diff --git a/core/fpdfapi/parser/BUILD.gn b/core/fpdfapi/parser/BUILD.gn index ad8a783..e3152d8 100644 --- a/core/fpdfapi/parser/BUILD.gn +++ b/core/fpdfapi/parser/BUILD.gn
@@ -1,4 +1,4 @@ -# Copyright 2018 The PDFium Authors. All rights reserved. +# Copyright 2018 The PDFium Authors # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. @@ -73,14 +73,16 @@ "fpdf_parser_decode.h", "fpdf_parser_utility.cpp", "fpdf_parser_utility.h", + "object_tree_traversal_util.cpp", + "object_tree_traversal_util.h", ] - configs += [ "../../../:pdfium_core_config" ] + configs += [ "../../../:pdfium_strict_config" ] deps = [ "../../../constants", "../../fdrm", "../../fxcodec", - "../../fxcrt", ] + public_deps = [ "../../fxcrt" ] allow_circular_includes_from = [] visibility = [ "../../../*" ] @@ -90,20 +92,36 @@ "cpdf_seekablemultistream.h", ] } - if (pdf_use_skia || pdf_use_skia_paths) { + if (pdf_use_skia) { deps += [ "../../fxge" ] allow_circular_includes_from += [ "../../fxge" ] } } +source_set("unit_test_support") { + testonly = true + sources = [ + "cpdf_test_document.cpp", + "cpdf_test_document.h", + ] + configs += [ "../../../:pdfium_strict_config" ] + deps = [ + ":parser", + "../page", + "../render", + ] +} + pdfium_unittest_source_set("unittests") { sources = [ "cpdf_array_unittest.cpp", "cpdf_cross_ref_avail_unittest.cpp", + "cpdf_dictionary_unittest.cpp", "cpdf_document_unittest.cpp", "cpdf_hint_tables_unittest.cpp", "cpdf_indirect_object_holder_unittest.cpp", "cpdf_object_avail_unittest.cpp", + "cpdf_object_stream_unittest.cpp", "cpdf_object_unittest.cpp", "cpdf_object_walker_unittest.cpp", "cpdf_page_object_avail_unittest.cpp", @@ -117,8 +135,10 @@ ] deps = [ ":parser", + ":unit_test_support", "../../../constants", "../page", + "../page:unit_test_support", "../render", ] pdfium_root_dir = "../../../" @@ -126,10 +146,6 @@ if (pdf_enable_xfa) { sources += [ "cpdf_seekablemultistream_unittest.cpp" ] } - if (is_clang) { - # Suppress no override warning for overridden functions. - cflags = [ "-Wno-inconsistent-missing-override" ] - } } pdfium_embeddertest_source_set("embeddertests") { @@ -137,7 +153,11 @@ "cpdf_parser_embeddertest.cpp", "cpdf_security_handler_embeddertest.cpp", "fpdf_parser_decode_embeddertest.cpp", + "object_tree_traversal_util_embeddertest.cpp", ] - deps = [ ":parser" ] + deps = [ + ":parser", + "../../fxge", + ] pdfium_root_dir = "../../../" }
diff --git a/core/fpdfapi/parser/cfdf_document.cpp b/core/fpdfapi/parser/cfdf_document.cpp index 054f999..5e9b6d3 100644 --- a/core/fpdfapi/parser/cfdf_document.cpp +++ b/core/fpdfapi/parser/cfdf_document.cpp
@@ -1,4 +1,4 @@ -// Copyright 2014 PDFium Authors. All rights reserved. +// Copyright 2014 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -13,8 +13,8 @@ #include "core/fpdfapi/parser/cpdf_dictionary.h" #include "core/fpdfapi/parser/cpdf_syntax_parser.h" #include "core/fpdfapi/parser/fpdf_parser_utility.h" -#include "core/fxcrt/cfx_readonlymemorystream.h" -#include "third_party/base/ptr_util.h" +#include "core/fxcrt/cfx_read_only_span_stream.h" +#include "core/fxcrt/fx_string_wrappers.h" #include "third_party/base/span.h" CFDF_Document::CFDF_Document() = default; @@ -22,36 +22,35 @@ CFDF_Document::~CFDF_Document() = default; std::unique_ptr<CFDF_Document> CFDF_Document::CreateNewDoc() { - auto pDoc = pdfium::MakeUnique<CFDF_Document>(); - pDoc->m_pRootDict.Reset(pDoc->NewIndirect<CPDF_Dictionary>()); + auto pDoc = std::make_unique<CFDF_Document>(); + pDoc->m_pRootDict = pDoc->NewIndirect<CPDF_Dictionary>(); pDoc->m_pRootDict->SetNewFor<CPDF_Dictionary>("FDF"); return pDoc; } std::unique_ptr<CFDF_Document> CFDF_Document::ParseMemory( pdfium::span<const uint8_t> span) { - auto pDoc = pdfium::MakeUnique<CFDF_Document>(); - pDoc->ParseStream(pdfium::MakeRetain<CFX_ReadOnlyMemoryStream>(span)); + auto pDoc = std::make_unique<CFDF_Document>(); + pDoc->ParseStream(pdfium::MakeRetain<CFX_ReadOnlySpanStream>(span)); return pDoc->m_pRootDict ? std::move(pDoc) : nullptr; } void CFDF_Document::ParseStream(RetainPtr<IFX_SeekableReadStream> pFile) { m_pFile = std::move(pFile); CPDF_SyntaxParser parser(m_pFile); - while (1) { - bool bNumber; - ByteString word = parser.GetNextWord(&bNumber); - if (bNumber) { - uint32_t objnum = FXSYS_atoui(word.c_str()); + while (true) { + CPDF_SyntaxParser::WordResult word_result = parser.GetNextWord(); + if (word_result.is_number) { + uint32_t objnum = FXSYS_atoui(word_result.word.c_str()); if (!objnum) break; - word = parser.GetNextWord(&bNumber); - if (!bNumber) + word_result = parser.GetNextWord(); + if (!word_result.is_number) break; - word = parser.GetNextWord(nullptr); - if (word != "obj") + word_result = parser.GetNextWord(); + if (word_result.word != "obj") break; RetainPtr<CPDF_Object> pObj = parser.GetObjectBody(this); @@ -59,17 +58,17 @@ break; ReplaceIndirectObjectIfHigherGeneration(objnum, std::move(pObj)); - word = parser.GetNextWord(nullptr); - if (word != "endobj") + word_result = parser.GetNextWord(); + if (word_result.word != "endobj") break; } else { - if (word != "trailer") + if (word_result.word != "trailer") break; RetainPtr<CPDF_Dictionary> pMainDict = ToDictionary(parser.GetObjectBody(this)); if (pMainDict) - m_pRootDict.Reset(pMainDict->GetDictFor("Root")); + m_pRootDict = pMainDict->GetMutableDictFor("Root"); break; } @@ -80,7 +79,7 @@ if (!m_pRootDict) return ByteString(); - std::ostringstream buf; + fxcrt::ostringstream buf; buf << "%FDF-1.2\r\n"; for (const auto& pair : *this) buf << pair.first << " 0 obj\r\n"
diff --git a/core/fpdfapi/parser/cfdf_document.h b/core/fpdfapi/parser/cfdf_document.h index cad94d0..bd0e72f 100644 --- a/core/fpdfapi/parser/cfdf_document.h +++ b/core/fpdfapi/parser/cfdf_document.h
@@ -1,4 +1,4 @@ -// Copyright 2016 PDFium Authors. All rights reserved. +// Copyright 2016 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -26,7 +26,8 @@ ~CFDF_Document() override; ByteString WriteToString() const; - CPDF_Dictionary* GetRoot() const { return m_pRootDict.Get(); } + const CPDF_Dictionary* GetRoot() const { return m_pRootDict.Get(); } + RetainPtr<CPDF_Dictionary> GetMutableRoot() const { return m_pRootDict; } private: void ParseStream(RetainPtr<IFX_SeekableReadStream> pFile);
diff --git a/core/fpdfapi/parser/cpdf_array.cpp b/core/fpdfapi/parser/cpdf_array.cpp index 0d66cb0..55b82e7 100644 --- a/core/fpdfapi/parser/cpdf_array.cpp +++ b/core/fpdfapi/parser/cpdf_array.cpp
@@ -1,4 +1,4 @@ -// Copyright 2016 PDFium Authors. All rights reserved. +// Copyright 2016 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -10,15 +10,16 @@ #include <utility> #include "core/fpdfapi/parser/cpdf_boolean.h" +#include "core/fpdfapi/parser/cpdf_dictionary.h" #include "core/fpdfapi/parser/cpdf_name.h" #include "core/fpdfapi/parser/cpdf_number.h" #include "core/fpdfapi/parser/cpdf_reference.h" #include "core/fpdfapi/parser/cpdf_stream.h" #include "core/fpdfapi/parser/cpdf_string.h" #include "core/fxcrt/fx_stream.h" -#include "third_party/base/logging.h" -#include "third_party/base/ptr_util.h" -#include "third_party/base/stl_util.h" +#include "third_party/base/check.h" +#include "third_party/base/containers/contains.h" +#include "third_party/base/notreached.h" CPDF_Array::CPDF_Array() = default; @@ -28,7 +29,7 @@ // Break cycles for cyclic references. m_ObjNum = kInvalidObjNum; for (auto& it : m_Objects) { - if (it && it->GetObjNum() == kInvalidObjNum) + if (it->GetObjNum() == kInvalidObjNum) it.Leak(); } } @@ -37,15 +38,7 @@ return kArray; } -bool CPDF_Array::IsArray() const { - return true; -} - -CPDF_Array* CPDF_Array::AsArray() { - return this; -} - -const CPDF_Array* CPDF_Array::AsArray() const { +CPDF_Array* CPDF_Array::AsMutableArray() { return this; } @@ -59,7 +52,7 @@ pVisited->insert(this); auto pCopy = pdfium::MakeRetain<CPDF_Array>(); for (const auto& pValue : m_Objects) { - if (!pdfium::ContainsKey(*pVisited, pValue.Get())) { + if (!pdfium::Contains(*pVisited, pValue.Get())) { std::set<const CPDF_Object*> visited(*pVisited); if (auto obj = pValue->CloneNonCyclic(bDirect, &visited)) pCopy->m_Objects.push_back(std::move(obj)); @@ -73,10 +66,10 @@ if (m_Objects.size() != 4) return rect; - rect.left = GetNumberAt(0); - rect.bottom = GetNumberAt(1); - rect.right = GetNumberAt(2); - rect.top = GetNumberAt(3); + rect.left = GetFloatAt(0); + rect.bottom = GetFloatAt(1); + rect.right = GetFloatAt(2); + rect.top = GetFloatAt(3); return rect; } @@ -84,35 +77,48 @@ if (m_Objects.size() != 6) return CFX_Matrix(); - return CFX_Matrix(GetNumberAt(0), GetNumberAt(1), GetNumberAt(2), - GetNumberAt(3), GetNumberAt(4), GetNumberAt(5)); + return CFX_Matrix(GetFloatAt(0), GetFloatAt(1), GetFloatAt(2), GetFloatAt(3), + GetFloatAt(4), GetFloatAt(5)); } -CPDF_Object* CPDF_Array::GetObjectAt(size_t index) { - if (index >= m_Objects.size()) - return nullptr; - return m_Objects[index].Get(); +absl::optional<size_t> CPDF_Array::Find(const CPDF_Object* pThat) const { + for (size_t i = 0; i < size(); ++i) { + if (GetDirectObjectAt(i) == pThat) + return i; + } + return absl::nullopt; } -const CPDF_Object* CPDF_Array::GetObjectAt(size_t index) const { - if (index >= m_Objects.size()) - return nullptr; - return m_Objects[index].Get(); +bool CPDF_Array::Contains(const CPDF_Object* pThat) const { + return Find(pThat).has_value(); } -CPDF_Object* CPDF_Array::GetDirectObjectAt(size_t index) { - if (index >= m_Objects.size()) - return nullptr; - return m_Objects[index]->GetDirect(); +CPDF_Object* CPDF_Array::GetMutableObjectAtInternal(size_t index) { + return index < m_Objects.size() ? m_Objects[index].Get() : nullptr; } -const CPDF_Object* CPDF_Array::GetDirectObjectAt(size_t index) const { - if (index >= m_Objects.size()) - return nullptr; - return m_Objects[index]->GetDirect(); +const CPDF_Object* CPDF_Array::GetObjectAtInternal(size_t index) const { + return const_cast<CPDF_Array*>(this)->GetMutableObjectAtInternal(index); } -ByteString CPDF_Array::GetStringAt(size_t index) const { +RetainPtr<CPDF_Object> CPDF_Array::GetMutableObjectAt(size_t index) { + return pdfium::WrapRetain(GetMutableObjectAtInternal(index)); +} + +RetainPtr<const CPDF_Object> CPDF_Array::GetObjectAt(size_t index) const { + return pdfium::WrapRetain(GetObjectAtInternal(index)); +} + +RetainPtr<const CPDF_Object> CPDF_Array::GetDirectObjectAt(size_t index) const { + return const_cast<CPDF_Array*>(this)->GetMutableDirectObjectAt(index); +} + +RetainPtr<CPDF_Object> CPDF_Array::GetMutableDirectObjectAt(size_t index) { + RetainPtr<CPDF_Object> pObj = GetMutableObjectAt(index); + return pObj ? pObj->GetMutableDirect() : nullptr; +} + +ByteString CPDF_Array::GetByteStringAt(size_t index) const { if (index >= m_Objects.size()) return ByteString(); return m_Objects[index]->GetString(); @@ -137,48 +143,51 @@ return m_Objects[index]->GetInteger(); } -float CPDF_Array::GetNumberAt(size_t index) const { +float CPDF_Array::GetFloatAt(size_t index) const { if (index >= m_Objects.size()) return 0; return m_Objects[index]->GetNumber(); } -CPDF_Dictionary* CPDF_Array::GetDictAt(size_t index) { - CPDF_Object* p = GetDirectObjectAt(index); +RetainPtr<CPDF_Dictionary> CPDF_Array::GetMutableDictAt(size_t index) { + RetainPtr<CPDF_Object> p = GetMutableDirectObjectAt(index); if (!p) return nullptr; - if (CPDF_Dictionary* pDict = p->AsDictionary()) - return pDict; - if (CPDF_Stream* pStream = p->AsStream()) - return pStream->GetDict(); + CPDF_Dictionary* pDict = p->AsMutableDictionary(); + if (pDict) + return pdfium::WrapRetain(pDict); + CPDF_Stream* pStream = p->AsMutableStream(); + if (pStream) + return pStream->GetMutableDict(); return nullptr; } -const CPDF_Dictionary* CPDF_Array::GetDictAt(size_t index) const { - const CPDF_Object* p = GetDirectObjectAt(index); - if (!p) - return nullptr; - if (const CPDF_Dictionary* pDict = p->AsDictionary()) - return pDict; - if (const CPDF_Stream* pStream = p->AsStream()) - return pStream->GetDict(); - return nullptr; +RetainPtr<const CPDF_Dictionary> CPDF_Array::GetDictAt(size_t index) const { + return const_cast<CPDF_Array*>(this)->GetMutableDictAt(index); } -CPDF_Stream* CPDF_Array::GetStreamAt(size_t index) { - return ToStream(GetDirectObjectAt(index)); +RetainPtr<CPDF_Stream> CPDF_Array::GetMutableStreamAt(size_t index) { + return ToStream(GetMutableDirectObjectAt(index)); } -const CPDF_Stream* CPDF_Array::GetStreamAt(size_t index) const { - return ToStream(GetDirectObjectAt(index)); +RetainPtr<const CPDF_Stream> CPDF_Array::GetStreamAt(size_t index) const { + return const_cast<CPDF_Array*>(this)->GetMutableStreamAt(index); } -CPDF_Array* CPDF_Array::GetArrayAt(size_t index) { - return ToArray(GetDirectObjectAt(index)); +RetainPtr<CPDF_Array> CPDF_Array::GetMutableArrayAt(size_t index) { + return ToArray(GetMutableDirectObjectAt(index)); } -const CPDF_Array* CPDF_Array::GetArrayAt(size_t index) const { - return ToArray(GetDirectObjectAt(index)); +RetainPtr<const CPDF_Array> CPDF_Array::GetArrayAt(size_t index) const { + return const_cast<CPDF_Array*>(this)->GetMutableArrayAt(index); +} + +RetainPtr<const CPDF_Number> CPDF_Array::GetNumberAt(size_t index) const { + return ToNumber(GetObjectAt(index)); +} + +RetainPtr<const CPDF_String> CPDF_Array::GetStringAt(size_t index) const { + return ToString(GetObjectAt(index)); } void CPDF_Array::Clear() { @@ -201,40 +210,52 @@ if (!m_Objects[index] || m_Objects[index]->IsReference()) return; - CPDF_Object* pNew = pHolder->AddIndirectObject(std::move(m_Objects[index])); - m_Objects[index] = pNew->MakeReference(pHolder); + pHolder->AddIndirectObject(m_Objects[index]); + m_Objects[index] = m_Objects[index]->MakeReference(pHolder); } -CPDF_Object* CPDF_Array::SetAt(size_t index, RetainPtr<CPDF_Object> pObj) { +void CPDF_Array::SetAt(size_t index, RetainPtr<CPDF_Object> pObj) { + (void)SetAtInternal(index, std::move(pObj)); +} + +void CPDF_Array::InsertAt(size_t index, RetainPtr<CPDF_Object> pObj) { + (void)InsertAtInternal(index, std::move(pObj)); +} + +void CPDF_Array::Append(RetainPtr<CPDF_Object> pObj) { + (void)AppendInternal(std::move(pObj)); +} + +CPDF_Object* CPDF_Array::SetAtInternal(size_t index, + RetainPtr<CPDF_Object> pObj) { CHECK(!IsLocked()); - ASSERT(!pObj || pObj->IsInline()); - if (index >= m_Objects.size()) { - NOTREACHED(); + CHECK(pObj); + CHECK(pObj->IsInline()); + if (index >= m_Objects.size()) return nullptr; - } + CPDF_Object* pRet = pObj.Get(); m_Objects[index] = std::move(pObj); return pRet; } -CPDF_Object* CPDF_Array::InsertAt(size_t index, RetainPtr<CPDF_Object> pObj) { +CPDF_Object* CPDF_Array::InsertAtInternal(size_t index, + RetainPtr<CPDF_Object> pObj) { CHECK(!IsLocked()); - CHECK(!pObj || pObj->IsInline()); + CHECK(pObj); + CHECK(pObj->IsInline()); + if (index > m_Objects.size()) + return nullptr; + CPDF_Object* pRet = pObj.Get(); - if (index >= m_Objects.size()) { - // Allocate space first. - m_Objects.resize(index + 1); - m_Objects[index] = std::move(pObj); - } else { - // Directly insert. - m_Objects.insert(m_Objects.begin() + index, std::move(pObj)); - } + m_Objects.insert(m_Objects.begin() + index, std::move(pObj)); return pRet; } -CPDF_Object* CPDF_Array::Add(RetainPtr<CPDF_Object> pObj) { +CPDF_Object* CPDF_Array::AppendInternal(RetainPtr<CPDF_Object> pObj) { CHECK(!IsLocked()); - CHECK(!pObj || pObj->IsInline()); + CHECK(pObj); + CHECK(pObj->IsInline()); CPDF_Object* pRet = pObj.Get(); m_Objects.push_back(std::move(pObj)); return pRet; @@ -257,6 +278,16 @@ m_pArray->m_LockCount++; } +CPDF_ArrayLocker::CPDF_ArrayLocker(RetainPtr<CPDF_Array> pArray) + : m_pArray(std::move(pArray)) { + m_pArray->m_LockCount++; +} + +CPDF_ArrayLocker::CPDF_ArrayLocker(RetainPtr<const CPDF_Array> pArray) + : m_pArray(std::move(pArray)) { + m_pArray->m_LockCount++; +} + CPDF_ArrayLocker::~CPDF_ArrayLocker() { m_pArray->m_LockCount--; }
diff --git a/core/fpdfapi/parser/cpdf_array.h b/core/fpdfapi/parser/cpdf_array.h index 2a12d99..ea9a815 100644 --- a/core/fpdfapi/parser/cpdf_array.h +++ b/core/fpdfapi/parser/cpdf_array.h
@@ -1,4 +1,4 @@ -// Copyright 2016 PDFium Authors. All rights reserved. +// Copyright 2016 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -7,7 +7,8 @@ #ifndef CORE_FPDFAPI_PARSER_CPDF_ARRAY_H_ #define CORE_FPDFAPI_PARSER_CPDF_ARRAY_H_ -#include <memory> +#include <stddef.h> + #include <set> #include <type_traits> #include <utility> @@ -17,94 +18,118 @@ #include "core/fpdfapi/parser/cpdf_object.h" #include "core/fxcrt/fx_coordinates.h" #include "core/fxcrt/retain_ptr.h" -#include "third_party/base/ptr_util.h" +#include "third_party/abseil-cpp/absl/types/optional.h" +#include "third_party/base/check.h" +// Arrays never contain nullptrs for objects within bounds, but some of the +// methods will tolerate out-of-bounds indices and return nullptr for those +// cases. class CPDF_Array final : public CPDF_Object { public: using const_iterator = std::vector<RetainPtr<CPDF_Object>>::const_iterator; - template <typename T, typename... Args> - friend RetainPtr<T> pdfium::MakeRetain(Args&&... args); + CONSTRUCT_VIA_MAKE_RETAIN; // CPDF_Object: Type GetType() const override; RetainPtr<CPDF_Object> Clone() const override; - bool IsArray() const override; - CPDF_Array* AsArray() override; - const CPDF_Array* AsArray() const override; + CPDF_Array* AsMutableArray() override; bool WriteTo(IFX_ArchiveStream* archive, const CPDF_Encryptor* encryptor) const override; bool IsEmpty() const { return m_Objects.empty(); } size_t size() const { return m_Objects.size(); } - CPDF_Object* GetObjectAt(size_t index); - const CPDF_Object* GetObjectAt(size_t index) const; - CPDF_Object* GetDirectObjectAt(size_t index); - const CPDF_Object* GetDirectObjectAt(size_t index) const; - ByteString GetStringAt(size_t index) const; + + // The Get*ObjectAt() methods tolerate out-of-bounds indices and return + // nullptr in those cases. Otherwise, for in-bound indices, the result + // is never nullptr. + RetainPtr<CPDF_Object> GetMutableObjectAt(size_t index); + RetainPtr<const CPDF_Object> GetObjectAt(size_t index) const; + + // The Get*DirectObjectAt() methods tolerate out-of-bounds indices and + // return nullptr in those cases. Furthermore, for reference objects that + // do not correspond to a valid indirect object, nullptr is returned. + RetainPtr<CPDF_Object> GetMutableDirectObjectAt(size_t index); + RetainPtr<const CPDF_Object> GetDirectObjectAt(size_t index) const; + + // The Get*At() methods tolerate out-of-bounds indices and return nullptr + // in those cases. Furthermore, these safely coerce to the sub-class, + // returning nullptr if the object at the location is of a different type. + ByteString GetByteStringAt(size_t index) const; WideString GetUnicodeTextAt(size_t index) const; bool GetBooleanAt(size_t index, bool bDefault) const; int GetIntegerAt(size_t index) const; - float GetNumberAt(size_t index) const; - CPDF_Dictionary* GetDictAt(size_t index); - const CPDF_Dictionary* GetDictAt(size_t index) const; - CPDF_Stream* GetStreamAt(size_t index); - const CPDF_Stream* GetStreamAt(size_t index) const; - CPDF_Array* GetArrayAt(size_t index); - const CPDF_Array* GetArrayAt(size_t index) const; - CFX_Matrix GetMatrix() const; - CFX_FloatRect GetRect() const; + float GetFloatAt(size_t index) const; + RetainPtr<CPDF_Dictionary> GetMutableDictAt(size_t index); + RetainPtr<const CPDF_Dictionary> GetDictAt(size_t index) const; + RetainPtr<CPDF_Stream> GetMutableStreamAt(size_t index); + RetainPtr<const CPDF_Stream> GetStreamAt(size_t index) const; + RetainPtr<CPDF_Array> GetMutableArrayAt(size_t index); + RetainPtr<const CPDF_Array> GetArrayAt(size_t index) const; + RetainPtr<const CPDF_Number> GetNumberAt(size_t index) const; + RetainPtr<const CPDF_String> GetStringAt(size_t index) const; - // Creates object owned by the array, returns unowned pointer to it. + CFX_FloatRect GetRect() const; + CFX_Matrix GetMatrix() const; + + absl::optional<size_t> Find(const CPDF_Object* pThat) const; + bool Contains(const CPDF_Object* pThat) const; + + // Creates object owned by the array, and returns a retained pointer to it. // We have special cases for objects that can intern strings from // a ByteStringPool. Prefer using these templates over direct calls - // to Add()/SetAt()/InsertAt() since by creating a new object with no + // to Append()/SetAt()/InsertAt() since by creating a new object with no // previous references, they ensure cycles can not be introduced. template <typename T, typename... Args> - typename std::enable_if<!CanInternStrings<T>::value, T*>::type AddNew( - Args&&... args) { - return static_cast<T*>( - Add(pdfium::MakeRetain<T>(std::forward<Args>(args)...))); + typename std::enable_if<!CanInternStrings<T>::value, RetainPtr<T>>::type + AppendNew(Args&&... args) { + return pdfium::WrapRetain(static_cast<T*>( + AppendInternal(pdfium::MakeRetain<T>(std::forward<Args>(args)...)))); } template <typename T, typename... Args> - typename std::enable_if<CanInternStrings<T>::value, T*>::type AddNew( - Args&&... args) { - return static_cast<T*>( - Add(pdfium::MakeRetain<T>(m_pPool, std::forward<Args>(args)...))); + typename std::enable_if<CanInternStrings<T>::value, RetainPtr<T>>::type + AppendNew(Args&&... args) { + return pdfium::WrapRetain(static_cast<T*>(AppendInternal( + pdfium::MakeRetain<T>(m_pPool, std::forward<Args>(args)...)))); } template <typename T, typename... Args> - typename std::enable_if<!CanInternStrings<T>::value, T*>::type SetNewAt( - size_t index, - Args&&... args) { - return static_cast<T*>( - SetAt(index, pdfium::MakeRetain<T>(std::forward<Args>(args)...))); + typename std::enable_if<!CanInternStrings<T>::value, RetainPtr<T>>::type + SetNewAt(size_t index, Args&&... args) { + return pdfium::WrapRetain(static_cast<T*>(SetAtInternal( + index, pdfium::MakeRetain<T>(std::forward<Args>(args)...)))); } template <typename T, typename... Args> - typename std::enable_if<CanInternStrings<T>::value, T*>::type SetNewAt( - size_t index, - Args&&... args) { - return static_cast<T*>(SetAt( - index, pdfium::MakeRetain<T>(m_pPool, std::forward<Args>(args)...))); + typename std::enable_if<CanInternStrings<T>::value, RetainPtr<T>>::type + SetNewAt(size_t index, Args&&... args) { + return pdfium::WrapRetain(static_cast<T*>(SetAtInternal( + index, pdfium::MakeRetain<T>(m_pPool, std::forward<Args>(args)...)))); } template <typename T, typename... Args> - typename std::enable_if<!CanInternStrings<T>::value, T*>::type InsertNewAt( - size_t index, - Args&&... args) { - return static_cast<T*>( - InsertAt(index, pdfium::MakeRetain<T>(std::forward<Args>(args)...))); + typename std::enable_if<!CanInternStrings<T>::value, RetainPtr<T>>::type + InsertNewAt(size_t index, Args&&... args) { + return pdfium::WrapRetain(static_cast<T*>(InsertAtInternal( + index, pdfium::MakeRetain<T>(std::forward<Args>(args)...)))); } template <typename T, typename... Args> - typename std::enable_if<CanInternStrings<T>::value, T*>::type InsertNewAt( - size_t index, - Args&&... args) { - return static_cast<T*>(InsertAt( - index, pdfium::MakeRetain<T>(m_pPool, std::forward<Args>(args)...))); + typename std::enable_if<CanInternStrings<T>::value, RetainPtr<T>>::type + InsertNewAt(size_t index, Args&&... args) { + return pdfium::WrapRetain(static_cast<T*>(InsertAtInternal( + index, pdfium::MakeRetain<T>(m_pPool, std::forward<Args>(args)...)))); } - // Takes ownership of |pObj|, returns unowned pointer to it. - CPDF_Object* Add(RetainPtr<CPDF_Object> pObj); - CPDF_Object* SetAt(size_t index, RetainPtr<CPDF_Object> pObj); - CPDF_Object* InsertAt(size_t index, RetainPtr<CPDF_Object> pObj); + // Adds non-null `pObj` to the end of the array, growing as appropriate. + void Append(RetainPtr<CPDF_Object> pObj); + + // Overwrites the object at `index` with non-null `pObj`, if it is + // in bounds. Otherwise, `index` is out of bounds, and `pObj` is + // not stored. + void SetAt(size_t index, RetainPtr<CPDF_Object> pObj); + + // Inserts non-null `pObj` at `index` and shifts by one position all of the + // objects beyond it like std::vector::insert(), if `index` is less than or + // equal to the current array size. Otherwise, `index` is out of bounds, + // and `pObj` is not stored. + void InsertAt(size_t index, RetainPtr<CPDF_Object> pObj); void Clear(); void RemoveAt(size_t index); @@ -119,6 +144,13 @@ explicit CPDF_Array(const WeakPtr<ByteStringPool>& pPool); ~CPDF_Array() override; + // No guarantees about result lifetime, use with caution. + const CPDF_Object* GetObjectAtInternal(size_t index) const; + CPDF_Object* GetMutableObjectAtInternal(size_t index); + CPDF_Object* AppendInternal(RetainPtr<CPDF_Object> pObj); + CPDF_Object* SetAtInternal(size_t index, RetainPtr<CPDF_Object> pObj); + CPDF_Object* InsertAtInternal(size_t index, RetainPtr<CPDF_Object> pObj); + RetainPtr<CPDF_Object> CloneNonCyclic( bool bDirect, std::set<const CPDF_Object*>* pVisited) const override; @@ -130,9 +162,12 @@ class CPDF_ArrayLocker { public: + FX_STACK_ALLOCATED(); using const_iterator = CPDF_Array::const_iterator; explicit CPDF_ArrayLocker(const CPDF_Array* pArray); + explicit CPDF_ArrayLocker(RetainPtr<CPDF_Array> pArray); + explicit CPDF_ArrayLocker(RetainPtr<const CPDF_Array> pArray); ~CPDF_ArrayLocker(); const_iterator begin() const { @@ -149,7 +184,7 @@ }; inline CPDF_Array* ToArray(CPDF_Object* obj) { - return obj ? obj->AsArray() : nullptr; + return obj ? obj->AsMutableArray() : nullptr; } inline const CPDF_Array* ToArray(const CPDF_Object* obj) { @@ -160,4 +195,8 @@ return RetainPtr<CPDF_Array>(ToArray(obj.Get())); } +inline RetainPtr<const CPDF_Array> ToArray(RetainPtr<const CPDF_Object> obj) { + return RetainPtr<const CPDF_Array>(ToArray(obj.Get())); +} + #endif // CORE_FPDFAPI_PARSER_CPDF_ARRAY_H_
diff --git a/core/fpdfapi/parser/cpdf_array_unittest.cpp b/core/fpdfapi/parser/cpdf_array_unittest.cpp index 457961f..9b3e841 100644 --- a/core/fpdfapi/parser/cpdf_array_unittest.cpp +++ b/core/fpdfapi/parser/cpdf_array_unittest.cpp
@@ -1,24 +1,25 @@ -// Copyright 2016 PDFium Authors. All rights reserved. +// Copyright 2016 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "core/fpdfapi/parser/cpdf_array.h" +#include <iterator> #include <memory> #include <utility> #include "core/fpdfapi/parser/cpdf_boolean.h" +#include "core/fpdfapi/parser/cpdf_dictionary.h" #include "core/fpdfapi/parser/cpdf_number.h" #include "core/fpdfapi/parser/cpdf_reference.h" #include "testing/gtest/include/gtest/gtest.h" -#include "third_party/base/ptr_util.h" -TEST(cpdf_array, GetBooleanAt) { +TEST(ArrayTest, GetBooleanAt) { auto arr = pdfium::MakeRetain<CPDF_Array>(); - arr->AddNew<CPDF_Boolean>(true); - arr->AddNew<CPDF_Boolean>(false); - arr->AddNew<CPDF_Number>(100); - arr->AddNew<CPDF_Number>(0); + arr->AppendNew<CPDF_Boolean>(true); + arr->AppendNew<CPDF_Boolean>(false); + arr->AppendNew<CPDF_Number>(100); + arr->AppendNew<CPDF_Number>(0); ASSERT_EQ(4u, arr->size()); EXPECT_TRUE(arr->GetBooleanAt(0, true)); @@ -33,92 +34,88 @@ EXPECT_FALSE(arr->GetBooleanAt(99, false)); } -TEST(cpdf_array, RemoveAt) { +TEST(ArrayTest, RemoveAt) { { const int elems[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; auto arr = pdfium::MakeRetain<CPDF_Array>(); - for (size_t i = 0; i < FX_ArraySize(elems); ++i) - arr->AddNew<CPDF_Number>(elems[i]); + for (size_t i = 0; i < std::size(elems); ++i) + arr->AppendNew<CPDF_Number>(elems[i]); for (size_t i = 0; i < 3; ++i) arr->RemoveAt(3); const int expected[] = {1, 2, 3, 7, 8, 9, 10}; - ASSERT_EQ(FX_ArraySize(expected), arr->size()); - for (size_t i = 0; i < FX_ArraySize(expected); ++i) + ASSERT_EQ(std::size(expected), arr->size()); + for (size_t i = 0; i < std::size(expected); ++i) EXPECT_EQ(expected[i], arr->GetIntegerAt(i)); arr->RemoveAt(4); arr->RemoveAt(4); const int expected2[] = {1, 2, 3, 7, 10}; - ASSERT_EQ(FX_ArraySize(expected2), arr->size()); - for (size_t i = 0; i < FX_ArraySize(expected2); ++i) + ASSERT_EQ(std::size(expected2), arr->size()); + for (size_t i = 0; i < std::size(expected2); ++i) EXPECT_EQ(expected2[i], arr->GetIntegerAt(i)); } { // When the range is out of bound, RemoveAt() has no effect. const int elems[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; auto arr = pdfium::MakeRetain<CPDF_Array>(); - for (size_t i = 0; i < FX_ArraySize(elems); ++i) - arr->AddNew<CPDF_Number>(elems[i]); + for (size_t i = 0; i < std::size(elems); ++i) + arr->AppendNew<CPDF_Number>(elems[i]); arr->RemoveAt(11); - EXPECT_EQ(FX_ArraySize(elems), arr->size()); + EXPECT_EQ(std::size(elems), arr->size()); } } -TEST(cpdf_array, Clear) { +TEST(ArrayTest, Clear) { const int elems[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; auto arr = pdfium::MakeRetain<CPDF_Array>(); EXPECT_EQ(0U, arr->size()); - for (size_t i = 0; i < FX_ArraySize(elems); ++i) - arr->AddNew<CPDF_Number>(elems[i]); - EXPECT_EQ(FX_ArraySize(elems), arr->size()); + for (size_t i = 0; i < std::size(elems); ++i) + arr->AppendNew<CPDF_Number>(elems[i]); + EXPECT_EQ(std::size(elems), arr->size()); arr->Clear(); EXPECT_EQ(0U, arr->size()); } -TEST(cpdf_array, InsertAt) { - { - const int elems[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; - auto arr = pdfium::MakeRetain<CPDF_Array>(); - for (size_t i = 0; i < FX_ArraySize(elems); ++i) - arr->InsertNewAt<CPDF_Number>(i, elems[i]); - ASSERT_EQ(FX_ArraySize(elems), arr->size()); - for (size_t i = 0; i < FX_ArraySize(elems); ++i) - EXPECT_EQ(elems[i], arr->GetIntegerAt(i)); - arr->InsertNewAt<CPDF_Number>(3, 33); - arr->InsertNewAt<CPDF_Number>(6, 55); - arr->InsertNewAt<CPDF_Number>(12, 12); - const int expected[] = {1, 2, 3, 33, 4, 5, 55, 6, 7, 8, 9, 10, 12}; - ASSERT_EQ(FX_ArraySize(expected), arr->size()); - for (size_t i = 0; i < FX_ArraySize(expected); ++i) - EXPECT_EQ(expected[i], arr->GetIntegerAt(i)); - } - { - // When the position to insert is beyond the upper bound, - // an element is inserted at that position while other unfilled - // positions have nullptr. - const int elems[] = {1, 2}; - auto arr = pdfium::MakeRetain<CPDF_Array>(); - for (size_t i = 0; i < FX_ArraySize(elems); ++i) - arr->InsertNewAt<CPDF_Number>(i, elems[i]); - arr->InsertNewAt<CPDF_Number>(10, 10); - ASSERT_EQ(11u, arr->size()); - for (size_t i = 0; i < FX_ArraySize(elems); ++i) - EXPECT_EQ(elems[i], arr->GetIntegerAt(i)); - for (size_t i = FX_ArraySize(elems); i < 10; ++i) - EXPECT_EQ(nullptr, arr->GetObjectAt(i)); - EXPECT_EQ(10, arr->GetIntegerAt(10)); - } +TEST(ArrayTest, SetAtBeyond) { + auto arr = pdfium::MakeRetain<CPDF_Array>(); + EXPECT_FALSE(arr->SetNewAt<CPDF_Number>(0, 0)); + EXPECT_TRUE(arr->InsertNewAt<CPDF_Number>(0, 0)); + EXPECT_FALSE(arr->SetNewAt<CPDF_Number>(1, 0)); } -TEST(cpdf_array, Clone) { +TEST(ArrayTest, InsertAt) { + const int elems[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; + auto arr = pdfium::MakeRetain<CPDF_Array>(); + for (size_t i = 0; i < std::size(elems); ++i) + arr->InsertNewAt<CPDF_Number>(i, elems[i]); + ASSERT_EQ(std::size(elems), arr->size()); + for (size_t i = 0; i < std::size(elems); ++i) + EXPECT_EQ(elems[i], arr->GetIntegerAt(i)); + arr->InsertNewAt<CPDF_Number>(3, 33); + arr->InsertNewAt<CPDF_Number>(6, 55); + arr->InsertNewAt<CPDF_Number>(12, 12); + const int expected[] = {1, 2, 3, 33, 4, 5, 55, 6, 7, 8, 9, 10, 12}; + ASSERT_EQ(std::size(expected), arr->size()); + for (size_t i = 0; i < std::size(expected); ++i) + EXPECT_EQ(expected[i], arr->GetIntegerAt(i)); +} + +TEST(ArrayTest, InsertAtBeyond) { + auto arr = pdfium::MakeRetain<CPDF_Array>(); + EXPECT_FALSE(arr->InsertNewAt<CPDF_Number>(1, 0)); + EXPECT_TRUE(arr->InsertNewAt<CPDF_Number>(0, 0)); + EXPECT_FALSE(arr->InsertNewAt<CPDF_Number>(2, 0)); +} + +TEST(ArrayTest, Clone) { { // Basic case. const int elems[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; auto arr = pdfium::MakeRetain<CPDF_Array>(); - for (size_t i = 0; i < FX_ArraySize(elems); ++i) + for (size_t i = 0; i < std::size(elems); ++i) arr->InsertNewAt<CPDF_Number>(i, elems[i]); RetainPtr<CPDF_Array> arr2 = ToArray(arr->Clone()); ASSERT_EQ(arr->size(), arr2->size()); - for (size_t i = 0; i < FX_ArraySize(elems); ++i) { + for (size_t i = 0; i < std::size(elems); ++i) { // Clone() always create new objects. EXPECT_NE(arr->GetObjectAt(i), arr2->GetObjectAt(i)); EXPECT_EQ(arr->GetIntegerAt(i), arr2->GetIntegerAt(i)); @@ -132,7 +129,7 @@ {1, 2, 3, 4, 5}, {10, 9, 8, 7, 6}, {11, 12, 13, 14, 15}}; auto arr = pdfium::MakeRetain<CPDF_Array>(); // Indirect references to indirect objects. - auto obj_holder = pdfium::MakeUnique<CPDF_IndirectObjectHolder>(); + auto obj_holder = std::make_unique<CPDF_IndirectObjectHolder>(); for (size_t i = 0; i < kNumOfRows; ++i) { auto arr_elem = pdfium::MakeRetain<CPDF_Array>(); for (size_t j = 0; j < kNumOfRowElems; ++j) { @@ -154,15 +151,15 @@ RetainPtr<CPDF_Array> arr2 = ToArray(arr->CloneDirectObject()); ASSERT_EQ(arr->size(), arr2->size()); for (size_t i = 0; i < kNumOfRows; ++i) { - CPDF_Array* arr_elem = arr->GetObjectAt(i)->AsArray(); - CPDF_Array* arr1_elem = arr1->GetObjectAt(i)->AsArray(); - CPDF_Array* arr2_elem = arr2->GetObjectAt(i)->AsArray(); + const CPDF_Array* arr_elem = arr->GetObjectAt(i)->AsArray(); + const CPDF_Array* arr1_elem = arr1->GetObjectAt(i)->AsArray(); + const CPDF_Array* arr2_elem = arr2->GetObjectAt(i)->AsArray(); EXPECT_NE(arr_elem, arr1_elem); EXPECT_NE(arr_elem, arr2_elem); for (size_t j = 0; j < kNumOfRowElems; ++j) { - auto* elem_obj = arr_elem->GetObjectAt(j); - auto* elem_obj1 = arr1_elem->GetObjectAt(j); - auto* elem_obj2 = arr2_elem->GetObjectAt(j); + auto elem_obj = arr_elem->GetObjectAt(j); + auto elem_obj1 = arr1_elem->GetObjectAt(j); + auto elem_obj2 = arr2_elem->GetObjectAt(j); // Results from not deferencing reference objects. EXPECT_NE(elem_obj, elem_obj1); EXPECT_TRUE(elem_obj1->IsReference()); @@ -181,7 +178,7 @@ for (size_t i = 0; i < kNumOfRows; ++i) { for (size_t j = 0; j < kNumOfRowElems; ++j) { // Results from not deferencing reference objects. - auto* elem_obj1 = arr1->GetObjectAt(i)->AsArray()->GetObjectAt(j); + auto elem_obj1 = arr1->GetObjectAt(i)->AsArray()->GetObjectAt(j); EXPECT_TRUE(elem_obj1->IsReference()); EXPECT_EQ(elems[i][j], elem_obj1->GetInteger()); // Results from deferencing reference objects. @@ -192,16 +189,51 @@ } } -TEST(cpdf_array, Iterator) { +TEST(ArrayTest, Find) { + auto arr = pdfium::MakeRetain<CPDF_Array>(); + auto dict0 = pdfium::MakeRetain<CPDF_Dictionary>(); + auto dict1 = pdfium::MakeRetain<CPDF_Dictionary>(); + auto dict2 = pdfium::MakeRetain<CPDF_Dictionary>(); + arr->Append(dict0); + arr->Append(dict1); + + absl::optional<size_t> maybe_found = arr->Find(nullptr); + EXPECT_FALSE(maybe_found.has_value()); + + maybe_found = arr->Find(dict0.Get()); + ASSERT_TRUE(maybe_found.has_value()); + EXPECT_EQ(0u, maybe_found.value()); + + maybe_found = arr->Find(dict1.Get()); + ASSERT_TRUE(maybe_found.has_value()); + EXPECT_EQ(1u, maybe_found.value()); + + maybe_found = arr->Find(dict2.Get()); + EXPECT_FALSE(maybe_found.has_value()); +} + +TEST(ArrayTest, Contains) { + auto arr = pdfium::MakeRetain<CPDF_Array>(); + auto dict0 = pdfium::MakeRetain<CPDF_Dictionary>(); + auto dict1 = pdfium::MakeRetain<CPDF_Dictionary>(); + auto dict2 = pdfium::MakeRetain<CPDF_Dictionary>(); + arr->Append(dict0); + arr->Append(dict1); + EXPECT_TRUE(arr->Contains(dict0.Get())); + EXPECT_TRUE(arr->Contains(dict1.Get())); + EXPECT_FALSE(arr->Contains(dict2.Get())); +} + +TEST(ArrayTest, Iterator) { const int elems[] = {-23, -11, 3, 455, 2345877, 0, 7895330, -12564334, 10000, -100000}; auto arr = pdfium::MakeRetain<CPDF_Array>(); - for (size_t i = 0; i < FX_ArraySize(elems); ++i) + for (size_t i = 0; i < std::size(elems); ++i) arr->InsertNewAt<CPDF_Number>(i, elems[i]); - size_t index = 0; - CPDF_ArrayLocker locker(arr.Get()); + size_t index = 0; + CPDF_ArrayLocker locker(arr); for (const auto& it : locker) EXPECT_EQ(elems[index++], it->AsNumber()->GetInteger()); - EXPECT_EQ(FX_ArraySize(elems), index); + EXPECT_EQ(std::size(elems), index); }
diff --git a/core/fpdfapi/parser/cpdf_boolean.cpp b/core/fpdfapi/parser/cpdf_boolean.cpp index b5e12eb..3404959 100644 --- a/core/fpdfapi/parser/cpdf_boolean.cpp +++ b/core/fpdfapi/parser/cpdf_boolean.cpp
@@ -1,4 +1,4 @@ -// Copyright 2016 PDFium Authors. All rights reserved. +// Copyright 2016 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -7,7 +7,6 @@ #include "core/fpdfapi/parser/cpdf_boolean.h" #include "core/fxcrt/fx_stream.h" -#include "third_party/base/ptr_util.h" CPDF_Boolean::CPDF_Boolean() = default; @@ -35,15 +34,7 @@ m_bValue = (str == "true"); } -bool CPDF_Boolean::IsBoolean() const { - return true; -} - -CPDF_Boolean* CPDF_Boolean::AsBoolean() { - return this; -} - -const CPDF_Boolean* CPDF_Boolean::AsBoolean() const { +CPDF_Boolean* CPDF_Boolean::AsMutableBoolean() { return this; }
diff --git a/core/fpdfapi/parser/cpdf_boolean.h b/core/fpdfapi/parser/cpdf_boolean.h index 8ef47ad..9cec390 100644 --- a/core/fpdfapi/parser/cpdf_boolean.h +++ b/core/fpdfapi/parser/cpdf_boolean.h
@@ -1,4 +1,4 @@ -// Copyright 2016 PDFium Authors. All rights reserved. +// Copyright 2016 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -7,16 +7,13 @@ #ifndef CORE_FPDFAPI_PARSER_CPDF_BOOLEAN_H_ #define CORE_FPDFAPI_PARSER_CPDF_BOOLEAN_H_ -#include <memory> - #include "core/fpdfapi/parser/cpdf_object.h" -#include "core/fxcrt/fx_string.h" -#include "core/fxcrt/fx_system.h" +#include "core/fxcrt/bytestring.h" +#include "core/fxcrt/retain_ptr.h" class CPDF_Boolean final : public CPDF_Object { public: - template <typename T, typename... Args> - friend RetainPtr<T> pdfium::MakeRetain(Args&&... args); + CONSTRUCT_VIA_MAKE_RETAIN; // CPDF_Object: Type GetType() const override; @@ -24,9 +21,7 @@ ByteString GetString() const override; int GetInteger() const override; void SetString(const ByteString& str) override; - bool IsBoolean() const override; - CPDF_Boolean* AsBoolean() override; - const CPDF_Boolean* AsBoolean() const override; + CPDF_Boolean* AsMutableBoolean() override; bool WriteTo(IFX_ArchiveStream* archive, const CPDF_Encryptor* encryptor) const override; @@ -39,7 +34,7 @@ }; inline CPDF_Boolean* ToBoolean(CPDF_Object* obj) { - return obj ? obj->AsBoolean() : nullptr; + return obj ? obj->AsMutableBoolean() : nullptr; } inline const CPDF_Boolean* ToBoolean(const CPDF_Object* obj) {
diff --git a/core/fpdfapi/parser/cpdf_cross_ref_avail.cpp b/core/fpdfapi/parser/cpdf_cross_ref_avail.cpp index a6de007..7f0b7fe 100644 --- a/core/fpdfapi/parser/cpdf_cross_ref_avail.cpp +++ b/core/fpdfapi/parser/cpdf_cross_ref_avail.cpp
@@ -1,19 +1,18 @@ -// Copyright 2017 PDFium Authors. All rights reserved. +// Copyright 2017 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "core/fpdfapi/parser/cpdf_cross_ref_avail.h" -#include <algorithm> -#include <memory> -#include <vector> - #include "core/fpdfapi/parser/cpdf_dictionary.h" -#include "core/fpdfapi/parser/cpdf_name.h" #include "core/fpdfapi/parser/cpdf_read_validator.h" #include "core/fpdfapi/parser/cpdf_reference.h" #include "core/fpdfapi/parser/cpdf_syntax_parser.h" #include "core/fpdfapi/parser/fpdf_parser_utility.h" +#include "third_party/base/check.h" +#include "third_party/base/containers/contains.h" +#include "third_party/base/notreached.h" +#include "third_party/base/numerics/safe_conversions.h" namespace { @@ -30,20 +29,20 @@ CPDF_CrossRefAvail::CPDF_CrossRefAvail(CPDF_SyntaxParser* parser, FX_FILESIZE last_crossref_offset) : parser_(parser), last_crossref_offset_(last_crossref_offset) { - ASSERT(parser_); + DCHECK(parser_); AddCrossRefForCheck(last_crossref_offset); } -CPDF_CrossRefAvail::~CPDF_CrossRefAvail() {} +CPDF_CrossRefAvail::~CPDF_CrossRefAvail() = default; CPDF_DataAvail::DocAvailStatus CPDF_CrossRefAvail::CheckAvail() { - if (current_status_ == CPDF_DataAvail::DataAvailable) - return CPDF_DataAvail::DataAvailable; + if (status_ == CPDF_DataAvail::kDataAvailable) + return CPDF_DataAvail::kDataAvailable; - const CPDF_ReadValidator::Session read_session(GetValidator()); + CPDF_ReadValidator::ScopedSession read_session(GetValidator()); while (true) { bool check_result = false; - switch (current_state_) { + switch (state_) { case State::kCrossRefCheck: check_result = CheckCrossRef(); break; @@ -56,7 +55,7 @@ case State::kDone: break; default: { - current_status_ = CPDF_DataAvail::DataError; + status_ = CPDF_DataAvail::kDataError; NOTREACHED(); break; } @@ -64,14 +63,14 @@ if (!check_result) break; - ASSERT(!GetValidator()->has_read_problems()); + DCHECK(!GetValidator()->has_read_problems()); } - return current_status_; + return status_; } bool CPDF_CrossRefAvail::CheckReadProblems() { if (GetValidator()->read_error()) { - current_status_ = CPDF_DataAvail::DataError; + status_ = CPDF_DataAvail::kDataError; return true; } return GetValidator()->has_unavailable_data(); @@ -80,13 +79,13 @@ bool CPDF_CrossRefAvail::CheckCrossRef() { if (cross_refs_for_check_.empty()) { // All cross refs were checked. - current_state_ = State::kDone; - current_status_ = CPDF_DataAvail::DataAvailable; + state_ = State::kDone; + status_ = CPDF_DataAvail::kDataAvailable; return true; } parser_->SetPos(cross_refs_for_check_.front()); - const ByteString first_word = parser_->PeekNextWord(nullptr); + const ByteString first_word = parser_->PeekNextWord(); if (CheckReadProblems()) return false; @@ -105,36 +104,36 @@ return false; if (keyword != kCrossRefKeyword) { - current_status_ = CPDF_DataAvail::DataError; + status_ = CPDF_DataAvail::kDataError; return false; } - current_state_ = State::kCrossRefV4ItemCheck; - current_offset_ = parser_->GetPos(); + state_ = State::kCrossRefV4ItemCheck; + offset_ = parser_->GetPos(); return true; } bool CPDF_CrossRefAvail::CheckCrossRefV4Item() { - parser_->SetPos(current_offset_); + parser_->SetPos(offset_); const ByteString keyword = parser_->GetKeyword(); if (CheckReadProblems()) return false; if (keyword.IsEmpty()) { - current_status_ = CPDF_DataAvail::DataError; + status_ = CPDF_DataAvail::kDataError; return false; } if (keyword == kTrailerKeyword) - current_state_ = State::kCrossRefV4TrailerCheck; + state_ = State::kCrossRefV4TrailerCheck; // Go to next item. - current_offset_ = parser_->GetPos(); + offset_ = parser_->GetPos(); return true; } bool CPDF_CrossRefAvail::CheckCrossRefV4Trailer() { - parser_->SetPos(current_offset_); + parser_->SetPos(offset_); RetainPtr<CPDF_Dictionary> trailer = ToDictionary(parser_->GetObjectBody(nullptr)); @@ -142,30 +141,29 @@ return false; if (!trailer) { - current_status_ = CPDF_DataAvail::DataError; + status_ = CPDF_DataAvail::kDataError; return false; } if (ToReference(trailer->GetObjectFor(kEncryptKey))) { - current_status_ = CPDF_DataAvail::DataError; + status_ = CPDF_DataAvail::kDataError; return false; } - const int32_t xrefpos = - GetDirectInteger(trailer.Get(), kPrevCrossRefFieldKey); - if (xrefpos && + const int32_t xrefpos = trailer->GetDirectIntegerFor(kPrevCrossRefFieldKey); + if (xrefpos > 0 && pdfium::base::IsValueInRangeForNumericType<FX_FILESIZE>(xrefpos)) AddCrossRefForCheck(static_cast<FX_FILESIZE>(xrefpos)); const int32_t stream_xref_offset = - GetDirectInteger(trailer.Get(), kPrevCrossRefStreamOffsetFieldKey); - if (stream_xref_offset && + trailer->GetDirectIntegerFor(kPrevCrossRefStreamOffsetFieldKey); + if (stream_xref_offset > 0 && pdfium::base::IsValueInRangeForNumericType<FX_FILESIZE>( stream_xref_offset)) AddCrossRefForCheck(static_cast<FX_FILESIZE>(stream_xref_offset)); // Goto check next crossref - current_state_ = State::kCrossRefCheck; + state_ = State::kCrossRefCheck; return true; } @@ -175,32 +173,32 @@ if (CheckReadProblems()) return false; - const CPDF_Dictionary* trailer = + RetainPtr<const CPDF_Dictionary> trailer = cross_ref && cross_ref->IsStream() ? cross_ref->GetDict() : nullptr; if (!trailer) { - current_status_ = CPDF_DataAvail::DataError; + status_ = CPDF_DataAvail::kDataError; return false; } if (ToReference(trailer->GetObjectFor(kEncryptKey))) { - current_status_ = CPDF_DataAvail::DataError; + status_ = CPDF_DataAvail::kDataError; return false; } - const CPDF_Name* type_name = ToName(trailer->GetObjectFor(kTypeFieldKey)); - if (type_name && type_name->GetString() == kXRefKeyword) { + if (trailer->GetNameFor(kTypeFieldKey) == kXRefKeyword) { const int32_t xrefpos = trailer->GetIntegerFor(kPrevCrossRefFieldKey); - if (xrefpos && - pdfium::base::IsValueInRangeForNumericType<FX_FILESIZE>(xrefpos)) + if (xrefpos > 0 && + pdfium::base::IsValueInRangeForNumericType<FX_FILESIZE>(xrefpos)) { AddCrossRefForCheck(static_cast<FX_FILESIZE>(xrefpos)); + } } // Goto check next crossref - current_state_ = State::kCrossRefCheck; + state_ = State::kCrossRefCheck; return true; } void CPDF_CrossRefAvail::AddCrossRefForCheck(FX_FILESIZE crossref_offset) { - if (registered_crossrefs_.count(crossref_offset)) + if (pdfium::Contains(registered_crossrefs_, crossref_offset)) return; cross_refs_for_check_.push(crossref_offset);
diff --git a/core/fpdfapi/parser/cpdf_cross_ref_avail.h b/core/fpdfapi/parser/cpdf_cross_ref_avail.h index e550410..276fab1 100644 --- a/core/fpdfapi/parser/cpdf_cross_ref_avail.h +++ b/core/fpdfapi/parser/cpdf_cross_ref_avail.h
@@ -1,4 +1,4 @@ -// Copyright 2017 PDFium Authors. All rights reserved. +// Copyright 2017 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -9,6 +9,7 @@ #include <set> #include "core/fpdfapi/parser/cpdf_data_avail.h" +#include "core/fxcrt/retain_ptr.h" #include "core/fxcrt/unowned_ptr.h" class CPDF_SyntaxParser; @@ -42,12 +43,11 @@ RetainPtr<CPDF_ReadValidator> GetValidator(); - UnownedPtr<CPDF_SyntaxParser> parser_; - const FX_FILESIZE last_crossref_offset_ = 0; - CPDF_DataAvail::DocAvailStatus current_status_ = - CPDF_DataAvail::DataNotAvailable; - State current_state_ = State::kCrossRefCheck; - FX_FILESIZE current_offset_ = 0; + UnownedPtr<CPDF_SyntaxParser> const parser_; + const FX_FILESIZE last_crossref_offset_; + CPDF_DataAvail::DocAvailStatus status_ = CPDF_DataAvail::kDataNotAvailable; + State state_ = State::kCrossRefCheck; + FX_FILESIZE offset_ = 0; std::queue<FX_FILESIZE> cross_refs_for_check_; std::set<FX_FILESIZE> registered_crossrefs_; };
diff --git a/core/fpdfapi/parser/cpdf_cross_ref_avail_unittest.cpp b/core/fpdfapi/parser/cpdf_cross_ref_avail_unittest.cpp index 6cdc3f1..57f3bd4 100644 --- a/core/fpdfapi/parser/cpdf_cross_ref_avail_unittest.cpp +++ b/core/fpdfapi/parser/cpdf_cross_ref_avail_unittest.cpp
@@ -1,4 +1,4 @@ -// Copyright 2017 PDFium Authors. All rights reserved. +// Copyright 2017 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -8,21 +8,20 @@ #include <string> #include "core/fpdfapi/parser/cpdf_syntax_parser.h" -#include "core/fxcrt/cfx_readonlymemorystream.h" +#include "core/fxcrt/cfx_read_only_span_stream.h" #include "testing/gtest/include/gtest/gtest.h" -#include "third_party/base/ptr_util.h" namespace { std::unique_ptr<CPDF_SyntaxParser> MakeParserForBuffer( pdfium::span<const uint8_t> buffer) { - return pdfium::MakeUnique<CPDF_SyntaxParser>( - pdfium::MakeRetain<CFX_ReadOnlyMemoryStream>(buffer)); + return std::make_unique<CPDF_SyntaxParser>( + pdfium::MakeRetain<CFX_ReadOnlySpanStream>(buffer)); } } // namespace -TEST(CPDF_CrossRefAvailTest, CheckCrossRefV4) { +TEST(CrossRefAvailTest, CheckCrossRefV4) { const unsigned char xref_table[] = "xref \n" "0 6 \n" @@ -39,13 +38,13 @@ const FX_FILESIZE last_crossref_offset = 0; auto parser = MakeParserForBuffer(xref_table); - auto cross_ref_avail = pdfium::MakeUnique<CPDF_CrossRefAvail>( - parser.get(), last_crossref_offset); + auto cross_ref_avail = + std::make_unique<CPDF_CrossRefAvail>(parser.get(), last_crossref_offset); - EXPECT_EQ(CPDF_DataAvail::DataAvailable, cross_ref_avail->CheckAvail()); + EXPECT_EQ(CPDF_DataAvail::kDataAvailable, cross_ref_avail->CheckAvail()); } -TEST(CPDF_CrossRefAvailTest, CheckCrossRefStream) { +TEST(CrossRefAvailTest, CheckCrossRefStream) { const unsigned char xref_stream[] = "16 0 obj\n" "<</Filter /FlateDecode>>" @@ -56,13 +55,13 @@ const FX_FILESIZE last_crossref_offset = 0; auto parser = MakeParserForBuffer(xref_stream); - auto cross_ref_avail = pdfium::MakeUnique<CPDF_CrossRefAvail>( - parser.get(), last_crossref_offset); + auto cross_ref_avail = + std::make_unique<CPDF_CrossRefAvail>(parser.get(), last_crossref_offset); - EXPECT_EQ(CPDF_DataAvail::DataAvailable, cross_ref_avail->CheckAvail()); + EXPECT_EQ(CPDF_DataAvail::kDataAvailable, cross_ref_avail->CheckAvail()); } -TEST(CPDF_CrossRefAvailTest, IncorrectStartOffset) { +TEST(CrossRefAvailTest, IncorrectStartOffset) { const unsigned char xref_stream[] = "16 0 obj\n" "<</Filter /FlateDecode>>" @@ -74,13 +73,13 @@ const FX_FILESIZE last_crossref_offset = 70000; auto parser = MakeParserForBuffer(xref_stream); - auto cross_ref_avail = pdfium::MakeUnique<CPDF_CrossRefAvail>( - parser.get(), last_crossref_offset); + auto cross_ref_avail = + std::make_unique<CPDF_CrossRefAvail>(parser.get(), last_crossref_offset); - EXPECT_EQ(CPDF_DataAvail::DataError, cross_ref_avail->CheckAvail()); + EXPECT_EQ(CPDF_DataAvail::kDataError, cross_ref_avail->CheckAvail()); } -TEST(CPDF_CrossRefAvailTest, IncorrectPrevOffset) { +TEST(CrossRefAvailTest, IncorrectPrevOffset) { const unsigned char xref_stream[] = "16 0 obj\n" "<</Type /XRef /Prev 70000>>" @@ -91,12 +90,12 @@ const FX_FILESIZE last_crossref_offset = 0; auto parser = MakeParserForBuffer(xref_stream); - auto cross_ref_avail = pdfium::MakeUnique<CPDF_CrossRefAvail>( - parser.get(), last_crossref_offset); - EXPECT_EQ(CPDF_DataAvail::DataError, cross_ref_avail->CheckAvail()); + auto cross_ref_avail = + std::make_unique<CPDF_CrossRefAvail>(parser.get(), last_crossref_offset); + EXPECT_EQ(CPDF_DataAvail::kDataError, cross_ref_avail->CheckAvail()); } -TEST(CPDF_CrossRefAvailTest, IncorrectPrevStreamOffset) { +TEST(CrossRefAvailTest, IncorrectPrevStreamOffset) { const unsigned char xref_table[] = "xref \n" "0 6 \n" @@ -113,24 +112,24 @@ const FX_FILESIZE last_crossref_offset = 0; auto parser = MakeParserForBuffer(xref_table); - auto cross_ref_avail = pdfium::MakeUnique<CPDF_CrossRefAvail>( - parser.get(), last_crossref_offset); - EXPECT_EQ(CPDF_DataAvail::DataError, cross_ref_avail->CheckAvail()); + auto cross_ref_avail = + std::make_unique<CPDF_CrossRefAvail>(parser.get(), last_crossref_offset); + EXPECT_EQ(CPDF_DataAvail::kDataError, cross_ref_avail->CheckAvail()); } -TEST(CPDF_CrossRefAvailTest, IncorrectData) { +TEST(CrossRefAvailTest, IncorrectData) { const unsigned char incorrect_data[] = "fiajaoilf w9ifaoihwoiafhja wfijaofijoiaw fhj oiawhfoiah " "wfoihoiwfghouiafghwoigahfi"; const FX_FILESIZE last_crossref_offset = 0; auto parser = MakeParserForBuffer(incorrect_data); - auto cross_ref_avail = pdfium::MakeUnique<CPDF_CrossRefAvail>( - parser.get(), last_crossref_offset); - EXPECT_EQ(CPDF_DataAvail::DataError, cross_ref_avail->CheckAvail()); + auto cross_ref_avail = + std::make_unique<CPDF_CrossRefAvail>(parser.get(), last_crossref_offset); + EXPECT_EQ(CPDF_DataAvail::kDataError, cross_ref_avail->CheckAvail()); } -TEST(CPDF_CrossRefAvailTest, ThreeCrossRefV4) { +TEST(CrossRefAvailTest, ThreeCrossRefV4) { char int_buffer[100]; std::string table = "pdf blah blah blah\n"; size_t cur_offset = table.size(); @@ -173,12 +172,12 @@ const FX_FILESIZE last_crossref_offset = static_cast<FX_FILESIZE>(cur_offset); auto parser = MakeParserForBuffer(pdfium::as_bytes(pdfium::make_span(table))); - auto cross_ref_avail = pdfium::MakeUnique<CPDF_CrossRefAvail>( - parser.get(), last_crossref_offset); - EXPECT_EQ(CPDF_DataAvail::DataAvailable, cross_ref_avail->CheckAvail()); + auto cross_ref_avail = + std::make_unique<CPDF_CrossRefAvail>(parser.get(), last_crossref_offset); + EXPECT_EQ(CPDF_DataAvail::kDataAvailable, cross_ref_avail->CheckAvail()); } -TEST(CPDF_CrossRefAvailTest, ThreeCrossRefV5) { +TEST(CrossRefAvailTest, ThreeCrossRefV5) { char int_buffer[100]; std::string table = "pdf blah blah blah\n"; size_t cur_offset = table.size(); @@ -217,12 +216,12 @@ const FX_FILESIZE last_crossref_offset = static_cast<FX_FILESIZE>(cur_offset); auto parser = MakeParserForBuffer(pdfium::as_bytes(pdfium::make_span(table))); - auto cross_ref_avail = pdfium::MakeUnique<CPDF_CrossRefAvail>( - parser.get(), last_crossref_offset); - EXPECT_EQ(CPDF_DataAvail::DataAvailable, cross_ref_avail->CheckAvail()); + auto cross_ref_avail = + std::make_unique<CPDF_CrossRefAvail>(parser.get(), last_crossref_offset); + EXPECT_EQ(CPDF_DataAvail::kDataAvailable, cross_ref_avail->CheckAvail()); } -TEST(CPDF_CrossRefAvailTest, Mixed) { +TEST(CrossRefAvailTest, Mixed) { char int_buffer[100]; std::string table = "pdf blah blah blah\n"; @@ -266,12 +265,12 @@ const FX_FILESIZE last_crossref_offset = last_v4_table_offset; auto parser = MakeParserForBuffer(pdfium::as_bytes(pdfium::make_span(table))); - auto cross_ref_avail = pdfium::MakeUnique<CPDF_CrossRefAvail>( - parser.get(), last_crossref_offset); - EXPECT_EQ(CPDF_DataAvail::DataAvailable, cross_ref_avail->CheckAvail()); + auto cross_ref_avail = + std::make_unique<CPDF_CrossRefAvail>(parser.get(), last_crossref_offset); + EXPECT_EQ(CPDF_DataAvail::kDataAvailable, cross_ref_avail->CheckAvail()); } -TEST(CPDF_CrossRefAvailTest, CrossRefV5IsNotStream) { +TEST(CrossRefAvailTest, CrossRefV5IsNotStream) { const unsigned char invalid_xref_stream[] = "16 0 obj\n" "[/array /object]\n" @@ -280,12 +279,12 @@ const FX_FILESIZE last_crossref_offset = 0; auto parser = MakeParserForBuffer(invalid_xref_stream); - auto cross_ref_avail = pdfium::MakeUnique<CPDF_CrossRefAvail>( - parser.get(), last_crossref_offset); - EXPECT_EQ(CPDF_DataAvail::DataError, cross_ref_avail->CheckAvail()); + auto cross_ref_avail = + std::make_unique<CPDF_CrossRefAvail>(parser.get(), last_crossref_offset); + EXPECT_EQ(CPDF_DataAvail::kDataError, cross_ref_avail->CheckAvail()); } -TEST(CPDF_CrossRefAvailTest, CrossRefV4WithEncryptRef) { +TEST(CrossRefAvailTest, CrossRefV4WithEncryptRef) { const unsigned char xref_table[] = "xref \n" "0 6 \n" @@ -303,12 +302,12 @@ const FX_FILESIZE last_crossref_offset = 0; auto parser = MakeParserForBuffer(xref_table); - auto cross_ref_avail = pdfium::MakeUnique<CPDF_CrossRefAvail>( - parser.get(), last_crossref_offset); - EXPECT_EQ(CPDF_DataAvail::DataError, cross_ref_avail->CheckAvail()); + auto cross_ref_avail = + std::make_unique<CPDF_CrossRefAvail>(parser.get(), last_crossref_offset); + EXPECT_EQ(CPDF_DataAvail::kDataError, cross_ref_avail->CheckAvail()); } -TEST(CPDF_CrossRefAvailTest, CrossRefStreamWithEncryptRef) { +TEST(CrossRefAvailTest, CrossRefStreamWithEncryptRef) { const unsigned char xref_stream[] = "16 0 obj\n" "<</Filter /FlateDecode /Encrypt 77 0 R>>" @@ -319,7 +318,7 @@ const FX_FILESIZE last_crossref_offset = 0; auto parser = MakeParserForBuffer(xref_stream); - auto cross_ref_avail = pdfium::MakeUnique<CPDF_CrossRefAvail>( - parser.get(), last_crossref_offset); - EXPECT_EQ(CPDF_DataAvail::DataError, cross_ref_avail->CheckAvail()); + auto cross_ref_avail = + std::make_unique<CPDF_CrossRefAvail>(parser.get(), last_crossref_offset); + EXPECT_EQ(CPDF_DataAvail::kDataError, cross_ref_avail->CheckAvail()); }
diff --git a/core/fpdfapi/parser/cpdf_cross_ref_table.cpp b/core/fpdfapi/parser/cpdf_cross_ref_table.cpp index bd25b6c..0bb5bb6 100644 --- a/core/fpdfapi/parser/cpdf_cross_ref_table.cpp +++ b/core/fpdfapi/parser/cpdf_cross_ref_table.cpp
@@ -1,15 +1,15 @@ -// Copyright 2018 PDFium Authors. All rights reserved. +// Copyright 2018 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "core/fpdfapi/parser/cpdf_cross_ref_table.h" #include <utility> -#include <vector> #include "core/fpdfapi/parser/cpdf_dictionary.h" #include "core/fpdfapi/parser/cpdf_parser.h" -#include "third_party/base/stl_util.h" +#include "third_party/base/containers/contains.h" +#include "third_party/base/notreached.h" // static std::unique_ptr<CPDF_CrossRefTable> CPDF_CrossRefTable::MergeUp( @@ -27,13 +27,16 @@ CPDF_CrossRefTable::CPDF_CrossRefTable() = default; -CPDF_CrossRefTable::CPDF_CrossRefTable(RetainPtr<CPDF_Dictionary> trailer) - : trailer_(std::move(trailer)) {} +CPDF_CrossRefTable::CPDF_CrossRefTable(RetainPtr<CPDF_Dictionary> trailer, + uint32_t trailer_object_number) + : trailer_(std::move(trailer)), + trailer_object_number_(trailer_object_number) {} CPDF_CrossRefTable::~CPDF_CrossRefTable() = default; void CPDF_CrossRefTable::AddCompressed(uint32_t obj_num, - uint32_t archive_obj_num) { + uint32_t archive_obj_num, + uint32_t archive_obj_index) { if (obj_num >= CPDF_Parser::kMaxObjectNumber || archive_obj_num >= CPDF_Parser::kMaxObjectNumber) { NOTREACHED(); @@ -48,7 +51,8 @@ return; info.type = ObjectType::kCompressed; - info.archive_obj_num = archive_obj_num; + info.archive.obj_num = archive_obj_num; + info.archive.obj_index = archive_obj_index; info.gennum = 0; objects_info_[archive_obj_num].type = ObjectType::kObjStream; @@ -88,8 +92,10 @@ info.pos = 0; } -void CPDF_CrossRefTable::SetTrailer(RetainPtr<CPDF_Dictionary> trailer) { +void CPDF_CrossRefTable::SetTrailer(RetainPtr<CPDF_Dictionary> trailer, + uint32_t trailer_object_number) { trailer_ = std::move(trailer); + trailer_object_number_ = trailer_object_number; } const CPDF_CrossRefTable::ObjectInfo* CPDF_CrossRefTable::GetObjectInfo( @@ -112,7 +118,7 @@ objects_info_.erase(objects_info_.lower_bound(objnum), objects_info_.end()); - if (!pdfium::ContainsKey(objects_info_, objnum - 1)) + if (!pdfium::Contains(objects_info_, objnum - 1)) objects_info_[objnum - 1].pos = 0; } @@ -154,5 +160,5 @@ new_trailer->SetFor("Prev", trailer_->RemoveFor("Prev")); for (const auto& key : new_trailer->GetKeys()) - trailer_->SetFor(key, new_trailer->RemoveFor(key)); + trailer_->SetFor(key, new_trailer->RemoveFor(key.AsStringView())); }
diff --git a/core/fpdfapi/parser/cpdf_cross_ref_table.h b/core/fpdfapi/parser/cpdf_cross_ref_table.h index 66a51de..246e129 100644 --- a/core/fpdfapi/parser/cpdf_cross_ref_table.h +++ b/core/fpdfapi/parser/cpdf_cross_ref_table.h
@@ -1,14 +1,16 @@ -// Copyright 2018 PDFium Authors. All rights reserved. +// Copyright 2018 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #ifndef CORE_FPDFAPI_PARSER_CPDF_CROSS_REF_TABLE_H_ #define CORE_FPDFAPI_PARSER_CPDF_CROSS_REF_TABLE_H_ +#include <stdint.h> + #include <map> #include <memory> -#include "core/fxcrt/fx_system.h" +#include "core/fxcrt/fx_types.h" #include "core/fxcrt/retain_ptr.h" class CPDF_Dictionary; @@ -25,16 +27,20 @@ }; struct ObjectInfo { - ObjectInfo() : pos(0), type(ObjectType::kFree), gennum(0) {} - // if type is ObjectType::kCompressed the archive_obj_num should be used. - // if type is ObjectType::kNotCompressed the pos should be used. - // In other cases its are unused. + ObjectInfo() = default; + + // If `type` is `ObjectType::kCompressed`, `archive` should be used. + // If `type` is `ObjectType::kNotCompressed`, `pos` should be used. + // In other cases, it is unused. union { - FX_FILESIZE pos; - uint32_t archive_obj_num; + FX_FILESIZE pos = 0; + struct { + uint32_t obj_num; + uint32_t obj_index; + } archive; }; - ObjectType type; - uint16_t gennum; + ObjectType type = ObjectType::kFree; + uint16_t gennum = 0; }; // Merge cross reference tables. Apply top on current. @@ -43,14 +49,19 @@ std::unique_ptr<CPDF_CrossRefTable> top); CPDF_CrossRefTable(); - explicit CPDF_CrossRefTable(RetainPtr<CPDF_Dictionary> trailer); + CPDF_CrossRefTable(RetainPtr<CPDF_Dictionary> trailer, + uint32_t trailer_object_number); ~CPDF_CrossRefTable(); - void AddCompressed(uint32_t obj_num, uint32_t archive_obj_num); + void AddCompressed(uint32_t obj_num, + uint32_t archive_obj_num, + uint32_t archive_obj_index); void AddNormal(uint32_t obj_num, uint16_t gen_num, FX_FILESIZE pos); void SetFree(uint32_t obj_num); - void SetTrailer(RetainPtr<CPDF_Dictionary> trailer); + void SetTrailer(RetainPtr<CPDF_Dictionary> trailer, + uint32_t trailer_object_number); + uint32_t trailer_object_number() const { return trailer_object_number_; } const CPDF_Dictionary* trailer() const { return trailer_.Get(); } CPDF_Dictionary* GetMutableTrailerForTesting() { return trailer_.Get(); } @@ -69,6 +80,10 @@ void UpdateTrailer(RetainPtr<CPDF_Dictionary> new_trailer); RetainPtr<CPDF_Dictionary> trailer_; + // `trailer_` can be the dictionary part of a XRef stream object. Since it is + // inline, it has no object number. Store the stream's object number, or 0 if + // there is none. + uint32_t trailer_object_number_ = 0; std::map<uint32_t, ObjectInfo> objects_info_; };
diff --git a/core/fpdfapi/parser/cpdf_crypto_handler.cpp b/core/fpdfapi/parser/cpdf_crypto_handler.cpp index a19cf0a..5404207 100644 --- a/core/fpdfapi/parser/cpdf_crypto_handler.cpp +++ b/core/fpdfapi/parser/cpdf_crypto_handler.cpp
@@ -1,4 +1,4 @@ -// Copyright 2014 PDFium Authors. All rights reserved. +// Copyright 2014 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -23,6 +23,8 @@ #include "core/fpdfapi/parser/cpdf_stream.h" #include "core/fpdfapi/parser/cpdf_stream_acc.h" #include "core/fpdfapi/parser/cpdf_string.h" +#include "third_party/base/check.h" +#include "third_party/base/check_op.h" namespace { @@ -36,64 +38,55 @@ const CPDF_Dictionary* dictionary) { if (!dictionary) return false; - const CPDF_Object* type_obj = dictionary->GetDirectObjectFor(kTypeKey); + RetainPtr<const CPDF_Object> type_obj = + dictionary->GetDirectObjectFor(kTypeKey); if (!type_obj) type_obj = dictionary->GetDirectObjectFor(pdfium::form_fields::kFT); return type_obj && type_obj->GetString() == pdfium::form_fields::kSig; } -void CPDF_CryptoHandler::CryptBlock(bool bEncrypt, - uint32_t objnum, - uint32_t gennum, - pdfium::span<const uint8_t> source, - uint8_t* dest_buf, - uint32_t& dest_size) { - if (m_Cipher == FXCIPHER_NONE) { +void CPDF_CryptoHandler::EncryptContent(uint32_t objnum, + uint32_t gennum, + pdfium::span<const uint8_t> source, + uint8_t* dest_buf, + size_t& dest_size) const { + if (m_Cipher == Cipher::kNone) { memcpy(dest_buf, source.data(), source.size()); return; } uint8_t realkey[16]; size_t realkeylen = sizeof(realkey); - if (m_Cipher != FXCIPHER_AES || m_KeyLen != 32) { + if (m_Cipher != Cipher::kAES || m_KeyLen != 32) { uint8_t key1[32]; PopulateKey(objnum, gennum, key1); - if (m_Cipher == FXCIPHER_AES) + if (m_Cipher == Cipher::kAES) memcpy(key1 + m_KeyLen + 5, "sAlT", 4); - size_t len = m_Cipher == FXCIPHER_AES ? m_KeyLen + 9 : m_KeyLen + 5; + size_t len = m_Cipher == Cipher::kAES ? m_KeyLen + 9 : m_KeyLen + 5; CRYPT_MD5Generate({key1, len}, realkey); realkeylen = std::min(m_KeyLen + 5, sizeof(realkey)); } - if (m_Cipher == FXCIPHER_AES) { + if (m_Cipher == Cipher::kAES) { CRYPT_AESSetKey(m_pAESContext.get(), - m_KeyLen == 32 ? m_EncryptKey : realkey, m_KeyLen, - bEncrypt); - if (bEncrypt) { - uint8_t iv[16]; - for (int i = 0; i < 16; i++) { - iv[i] = (uint8_t)rand(); - } - CRYPT_AESSetIV(m_pAESContext.get(), iv); - memcpy(dest_buf, iv, 16); - int nblocks = source.size() / 16; - CRYPT_AESEncrypt(m_pAESContext.get(), dest_buf + 16, source.data(), - nblocks * 16); - uint8_t padding[16]; - memcpy(padding, source.data() + nblocks * 16, source.size() % 16); - memset(padding + source.size() % 16, 16 - source.size() % 16, - 16 - source.size() % 16); - CRYPT_AESEncrypt(m_pAESContext.get(), dest_buf + nblocks * 16 + 16, - padding, 16); - dest_size = 32 + nblocks * 16; - } else { - CRYPT_AESSetIV(m_pAESContext.get(), source.data()); - CRYPT_AESDecrypt(m_pAESContext.get(), dest_buf, source.data() + 16, - source.size() - 16); - dest_size = source.size() - 16; - dest_size -= dest_buf[dest_size - 1]; + m_KeyLen == 32 ? m_EncryptKey : realkey, m_KeyLen); + uint8_t iv[16]; + for (int i = 0; i < 16; i++) { + iv[i] = (uint8_t)rand(); } + CRYPT_AESSetIV(m_pAESContext.get(), iv); + memcpy(dest_buf, iv, 16); + int nblocks = source.size() / 16; + CRYPT_AESEncrypt(m_pAESContext.get(), dest_buf + 16, source.data(), + nblocks * 16); + uint8_t padding[16]; + memcpy(padding, source.data() + nblocks * 16, source.size() % 16); + memset(padding + source.size() % 16, 16 - source.size() % 16, + 16 - source.size() % 16); + CRYPT_AESEncrypt(m_pAESContext.get(), dest_buf + nblocks * 16 + 16, padding, + 16); + dest_size = 32 + nblocks * 16; } else { - ASSERT(dest_size == source.size()); + DCHECK_EQ(dest_size, source.size()); if (dest_buf != source.data()) memcpy(dest_buf, source.data(), source.size()); CRYPT_ArcFourCryptBlock({dest_buf, dest_size}, {realkey, realkeylen}); @@ -107,47 +100,33 @@ uint8_t m_Block[16]; }; -void* CPDF_CryptoHandler::CryptStart(uint32_t objnum, - uint32_t gennum, - bool bEncrypt) { - if (m_Cipher == FXCIPHER_NONE) { +void* CPDF_CryptoHandler::DecryptStart(uint32_t objnum, uint32_t gennum) { + if (m_Cipher == Cipher::kNone) return this; - } - if (m_Cipher == FXCIPHER_AES && m_KeyLen == 32) { + + if (m_Cipher == Cipher::kAES && m_KeyLen == 32) { AESCryptContext* pContext = FX_Alloc(AESCryptContext, 1); pContext->m_bIV = true; pContext->m_BlockOffset = 0; - CRYPT_AESSetKey(&pContext->m_Context, m_EncryptKey, 32, bEncrypt); - if (bEncrypt) { - for (int i = 0; i < 16; i++) { - pContext->m_Block[i] = (uint8_t)rand(); - } - CRYPT_AESSetIV(&pContext->m_Context, pContext->m_Block); - } + CRYPT_AESSetKey(&pContext->m_Context, m_EncryptKey, 32); return pContext; } uint8_t key1[48]; PopulateKey(objnum, gennum, key1); - if (m_Cipher == FXCIPHER_AES) + if (m_Cipher == Cipher::kAES) memcpy(key1 + m_KeyLen + 5, "sAlT", 4); uint8_t realkey[16]; - size_t len = m_Cipher == FXCIPHER_AES ? m_KeyLen + 9 : m_KeyLen + 5; + size_t len = m_Cipher == Cipher::kAES ? m_KeyLen + 9 : m_KeyLen + 5; CRYPT_MD5Generate({key1, len}, realkey); size_t realkeylen = std::min(m_KeyLen + 5, sizeof(realkey)); - if (m_Cipher == FXCIPHER_AES) { + if (m_Cipher == Cipher::kAES) { AESCryptContext* pContext = FX_Alloc(AESCryptContext, 1); pContext->m_bIV = true; pContext->m_BlockOffset = 0; - CRYPT_AESSetKey(&pContext->m_Context, realkey, 16, bEncrypt); - if (bEncrypt) { - for (int i = 0; i < 16; i++) { - pContext->m_Block[i] = (uint8_t)rand(); - } - CRYPT_AESSetIV(&pContext->m_Context, pContext->m_Block); - } + CRYPT_AESSetKey(&pContext->m_Context, realkey, 16); return pContext; } CRYPT_rc4_context* pContext = FX_Alloc(CRYPT_rc4_context, 1); @@ -155,32 +134,28 @@ return pContext; } -bool CPDF_CryptoHandler::CryptStream(void* context, - pdfium::span<const uint8_t> source, - CFX_BinaryBuf& dest_buf, - bool bEncrypt) { +bool CPDF_CryptoHandler::DecryptStream(void* context, + pdfium::span<const uint8_t> source, + BinaryBuffer& dest_buf) { if (!context) return false; - if (m_Cipher == FXCIPHER_NONE) { - dest_buf.AppendBlock(source.data(), source.size()); + if (m_Cipher == Cipher::kNone) { + dest_buf.AppendSpan(source); return true; } - if (m_Cipher == FXCIPHER_RC4) { - int old_size = dest_buf.GetSize(); - dest_buf.AppendBlock(source.data(), source.size()); - CRYPT_ArcFourCrypt(static_cast<CRYPT_rc4_context*>(context), - dest_buf.GetSpan().subspan(old_size, source.size())); + if (m_Cipher == Cipher::kRC4) { + size_t old_size = dest_buf.GetSize(); + dest_buf.AppendSpan(source); + CRYPT_ArcFourCrypt( + static_cast<CRYPT_rc4_context*>(context), + dest_buf.GetMutableSpan().subspan(old_size, source.size())); return true; } AESCryptContext* pContext = static_cast<AESCryptContext*>(context); - if (pContext->m_bIV && bEncrypt) { - dest_buf.AppendBlock(pContext->m_Block, 16); - pContext->m_bIV = false; - } uint32_t src_off = 0; uint32_t src_left = source.size(); - while (1) { + while (true) { uint32_t copy_size = 16 - pContext->m_BlockOffset; if (copy_size > src_left) { copy_size = src_left; @@ -191,20 +166,15 @@ src_left -= copy_size; pContext->m_BlockOffset += copy_size; if (pContext->m_BlockOffset == 16) { - if (!bEncrypt && pContext->m_bIV) { + if (pContext->m_bIV) { CRYPT_AESSetIV(&pContext->m_Context, pContext->m_Block); pContext->m_bIV = false; pContext->m_BlockOffset = 0; } else if (src_off < source.size()) { uint8_t block_buf[16]; - if (bEncrypt) { - CRYPT_AESEncrypt(&pContext->m_Context, block_buf, pContext->m_Block, - 16); - } else { - CRYPT_AESDecrypt(&pContext->m_Context, block_buf, pContext->m_Block, - 16); - } - dest_buf.AppendBlock(block_buf, 16); + CRYPT_AESDecrypt(&pContext->m_Context, block_buf, pContext->m_Block, + 16); + dest_buf.AppendSpan(block_buf); pContext->m_BlockOffset = 0; } } @@ -214,37 +184,25 @@ } return true; } -bool CPDF_CryptoHandler::CryptFinish(void* context, - CFX_BinaryBuf& dest_buf, - bool bEncrypt) { - if (!context) { + +bool CPDF_CryptoHandler::DecryptFinish(void* context, BinaryBuffer& dest_buf) { + if (!context) return false; - } - if (m_Cipher == FXCIPHER_NONE) { + + if (m_Cipher == Cipher::kNone) return true; - } - if (m_Cipher == FXCIPHER_RC4) { + + if (m_Cipher == Cipher::kRC4) { FX_Free(context); return true; } auto* pContext = static_cast<AESCryptContext*>(context); - if (bEncrypt) { - uint8_t block_buf[16]; - if (pContext->m_BlockOffset == 16) { - CRYPT_AESEncrypt(&pContext->m_Context, block_buf, pContext->m_Block, 16); - dest_buf.AppendBlock(block_buf, 16); - pContext->m_BlockOffset = 0; - } - memset(pContext->m_Block + pContext->m_BlockOffset, - (uint8_t)(16 - pContext->m_BlockOffset), - 16 - pContext->m_BlockOffset); - CRYPT_AESEncrypt(&pContext->m_Context, block_buf, pContext->m_Block, 16); - dest_buf.AppendBlock(block_buf, 16); - } else if (pContext->m_BlockOffset == 16) { + if (pContext->m_BlockOffset == 16) { uint8_t block_buf[16]; CRYPT_AESDecrypt(&pContext->m_Context, block_buf, pContext->m_Block, 16); - if (block_buf[15] <= 16) { - dest_buf.AppendBlock(block_buf, 16 - block_buf[15]); + if (block_buf[15] < 16) { + dest_buf.AppendSpan( + pdfium::make_span(block_buf).first(16 - block_buf[15])); } } FX_Free(pContext); @@ -254,22 +212,19 @@ ByteString CPDF_CryptoHandler::Decrypt(uint32_t objnum, uint32_t gennum, const ByteString& str) { - CFX_BinaryBuf dest_buf; + BinaryBuffer dest_buf; void* context = DecryptStart(objnum, gennum); DecryptStream(context, str.raw_span(), dest_buf); DecryptFinish(context, dest_buf); - return ByteString(dest_buf.GetBuffer(), dest_buf.GetSize()); + return ByteString(dest_buf.GetSpan()); } -void* CPDF_CryptoHandler::DecryptStart(uint32_t objnum, uint32_t gennum) { - return CryptStart(objnum, gennum, false); -} -uint32_t CPDF_CryptoHandler::DecryptGetSize(uint32_t src_size) { - return m_Cipher == FXCIPHER_AES ? src_size - 16 : src_size; +size_t CPDF_CryptoHandler::DecryptGetSize(size_t src_size) { + return m_Cipher == Cipher::kAES ? src_size - 16 : src_size; } bool CPDF_CryptoHandler::IsCipherAES() const { - return m_Cipher == FXCIPHER_AES; + return m_Cipher == Cipher::kAES; } bool CPDF_CryptoHandler::DecryptObjectTree(RetainPtr<CPDF_Object> object) { @@ -278,19 +233,18 @@ struct MayBeSignature { const CPDF_Dictionary* parent; - CPDF_Object* contents; + RetainPtr<CPDF_Object> contents; }; std::stack<MayBeSignature> may_be_sign_dictionaries; const uint32_t obj_num = object->GetObjNum(); const uint32_t gen_num = object->GetGenNum(); - CPDF_Object* object_to_decrypt = object.Get(); + RetainPtr<CPDF_Object> object_to_decrypt = object; while (object_to_decrypt) { - CPDF_NonConstObjectWalker walker(object_to_decrypt); - object_to_decrypt = nullptr; - while (CPDF_Object* child = walker.GetNext()) { - const CPDF_Dictionary* parent_dict = + CPDF_NonConstObjectWalker walker(std::move(object_to_decrypt)); + while (RetainPtr<CPDF_Object> child = walker.GetNext()) { + RetainPtr<const CPDF_Dictionary> parent_dict = walker.GetParent() ? walker.GetParent()->GetDict() : nullptr; if (walker.dictionary_key() == kContentsKey && (parent_dict->KeyExist(kTypeKey) || @@ -301,21 +255,22 @@ // Temporary skip it, to prevent signature corruption. // It will be decrypted on next interations, if this is not contents of // signature dictionary. - may_be_sign_dictionaries.push(MayBeSignature({parent_dict, child})); + may_be_sign_dictionaries.push({parent_dict.Get(), std::move(child)}); walker.SkipWalkIntoCurrentObject(); continue; } // Strings decryption. if (child->IsString()) { // TODO(art-snake): Move decryption into the CPDF_String class. - CPDF_String* str = child->AsString(); + CPDF_String* str = child->AsMutableString(); str->SetString(Decrypt(obj_num, gen_num, str->GetString())); } // Stream decryption. if (child->IsStream()) { // TODO(art-snake): Move decryption into the CPDF_Stream class. - CPDF_Stream* stream = child->AsStream(); - auto stream_access = pdfium::MakeRetain<CPDF_StreamAcc>(stream); + CPDF_Stream* stream = child->AsMutableStream(); + auto stream_access = + pdfium::MakeRetain<CPDF_StreamAcc>(pdfium::WrapRetain(stream)); stream_access->LoadAllDataRaw(); if (IsCipherAES() && stream_access->GetSize() < 16) { @@ -323,7 +278,7 @@ continue; } - CFX_BinaryBuf decrypted_buf; + BinaryBuffer decrypted_buf; decrypted_buf.EstimateSize(DecryptGetSize(stream_access->GetSize())); void* context = DecryptStart(obj_num, gen_num); @@ -331,8 +286,7 @@ DecryptStream(context, stream_access->GetSpan(), decrypted_buf); decrypt_result &= DecryptFinish(context, decrypted_buf); if (decrypt_result) { - const uint32_t decrypted_size = decrypted_buf.GetSize(); - stream->TakeData(decrypted_buf.DetachBuffer(), decrypted_size); + stream->TakeData(decrypted_buf.DetachBuffer()); } else { // Decryption failed, set the stream to empty stream->SetData({}); @@ -353,43 +307,24 @@ return true; } -bool CPDF_CryptoHandler::DecryptStream(void* context, - pdfium::span<const uint8_t> source, - CFX_BinaryBuf& dest_buf) { - return CryptStream(context, source, dest_buf, false); -} - -bool CPDF_CryptoHandler::DecryptFinish(void* context, CFX_BinaryBuf& dest_buf) { - return CryptFinish(context, dest_buf, false); -} - size_t CPDF_CryptoHandler::EncryptGetSize( pdfium::span<const uint8_t> source) const { - return m_Cipher == FXCIPHER_AES ? source.size() + 32 : source.size(); + return m_Cipher == Cipher::kAES ? source.size() + 32 : source.size(); } -bool CPDF_CryptoHandler::EncryptContent(uint32_t objnum, - uint32_t gennum, - pdfium::span<const uint8_t> source, - uint8_t* dest_buf, - uint32_t& dest_size) { - CryptBlock(true, objnum, gennum, source, dest_buf, dest_size); - return true; -} - -CPDF_CryptoHandler::CPDF_CryptoHandler(int cipher, +CPDF_CryptoHandler::CPDF_CryptoHandler(Cipher cipher, const uint8_t* key, size_t keylen) : m_KeyLen(std::min<size_t>(keylen, 32)), m_Cipher(cipher) { - ASSERT(cipher != FXCIPHER_AES || keylen == 16 || keylen == 24 || + DCHECK(cipher != Cipher::kAES || keylen == 16 || keylen == 24 || keylen == 32); - ASSERT(cipher != FXCIPHER_AES2 || keylen == 32); - ASSERT(cipher != FXCIPHER_RC4 || (keylen >= 5 && keylen <= 16)); + DCHECK(cipher != Cipher::kAES2 || keylen == 32); + DCHECK(cipher != Cipher::kRC4 || (keylen >= 5 && keylen <= 16)); - if (m_Cipher != FXCIPHER_NONE) + if (m_Cipher != Cipher::kNone) memcpy(m_EncryptKey, key, m_KeyLen); - if (m_Cipher == FXCIPHER_AES) + if (m_Cipher == Cipher::kAES) m_pAESContext.reset(FX_Alloc(CRYPT_aes_context, 1)); } @@ -397,7 +332,7 @@ void CPDF_CryptoHandler::PopulateKey(uint32_t objnum, uint32_t gennum, - uint8_t* key) { + uint8_t* key) const { memcpy(key, m_EncryptKey, m_KeyLen); key[m_KeyLen + 0] = (uint8_t)objnum; key[m_KeyLen + 1] = (uint8_t)(objnum >> 8);
diff --git a/core/fpdfapi/parser/cpdf_crypto_handler.h b/core/fpdfapi/parser/cpdf_crypto_handler.h index edfba97..b8f938c 100644 --- a/core/fpdfapi/parser/cpdf_crypto_handler.h +++ b/core/fpdfapi/parser/cpdf_crypto_handler.h
@@ -1,4 +1,4 @@ -// Copyright 2016 PDFium Authors. All rights reserved. +// Copyright 2016 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -7,63 +7,59 @@ #ifndef CORE_FPDFAPI_PARSER_CPDF_CRYPTO_HANDLER_H_ #define CORE_FPDFAPI_PARSER_CPDF_CRYPTO_HANDLER_H_ +#include <stddef.h> +#include <stdint.h> + #include <memory> #include "core/fdrm/fx_crypt.h" -#include "core/fxcrt/cfx_binarybuf.h" +#include "core/fxcrt/binary_buffer.h" +#include "core/fxcrt/bytestring.h" #include "core/fxcrt/fx_memory_wrappers.h" -#include "core/fxcrt/fx_string.h" -#include "core/fxcrt/fx_system.h" +#include "core/fxcrt/retain_ptr.h" #include "third_party/base/span.h" class CPDF_Dictionary; class CPDF_Object; -class CPDF_SecurityHandler; class CPDF_CryptoHandler { public: - CPDF_CryptoHandler(int cipher, const uint8_t* key, size_t keylen); - ~CPDF_CryptoHandler(); + enum class Cipher { + kNone = 0, + kRC4 = 1, + kAES = 2, + kAES2 = 3, + }; static bool IsSignatureDictionary(const CPDF_Dictionary* dictionary); + CPDF_CryptoHandler(Cipher cipher, const uint8_t* key, size_t keylen); + ~CPDF_CryptoHandler(); + bool DecryptObjectTree(RetainPtr<CPDF_Object> object); size_t EncryptGetSize(pdfium::span<const uint8_t> source) const; - bool EncryptContent(uint32_t objnum, + void EncryptContent(uint32_t objnum, uint32_t gennum, pdfium::span<const uint8_t> source, uint8_t* dest_buf, - uint32_t& dest_size); + size_t& dest_size) const; bool IsCipherAES() const; private: - uint32_t DecryptGetSize(uint32_t src_size); + size_t DecryptGetSize(size_t src_size); void* DecryptStart(uint32_t objnum, uint32_t gennum); ByteString Decrypt(uint32_t objnum, uint32_t gennum, const ByteString& str); bool DecryptStream(void* context, pdfium::span<const uint8_t> source, - CFX_BinaryBuf& dest_buf); - bool DecryptFinish(void* context, CFX_BinaryBuf& dest_buf); - - void PopulateKey(uint32_t objnum, uint32_t gennum, uint8_t* key); - void CryptBlock(bool bEncrypt, - uint32_t objnum, - uint32_t gennum, - pdfium::span<const uint8_t> source, - uint8_t* dest_buf, - uint32_t& dest_size); - void* CryptStart(uint32_t objnum, uint32_t gennum, bool bEncrypt); - bool CryptStream(void* context, - pdfium::span<const uint8_t> source, - CFX_BinaryBuf& dest_buf, - bool bEncrypt); - bool CryptFinish(void* context, CFX_BinaryBuf& dest_buf, bool bEncrypt); + BinaryBuffer& dest_buf); + bool DecryptFinish(void* context, BinaryBuffer& dest_buf); + void PopulateKey(uint32_t objnum, uint32_t gennum, uint8_t* key) const; const size_t m_KeyLen; - const int m_Cipher; + const Cipher m_Cipher; std::unique_ptr<CRYPT_aes_context, FxFreeDeleter> m_pAESContext; - uint8_t m_EncryptKey[32]; + uint8_t m_EncryptKey[32] = {}; }; #endif // CORE_FPDFAPI_PARSER_CPDF_CRYPTO_HANDLER_H_
diff --git a/core/fpdfapi/parser/cpdf_data_avail.cpp b/core/fpdfapi/parser/cpdf_data_avail.cpp index 457ae61..7db348a 100644 --- a/core/fpdfapi/parser/cpdf_data_avail.cpp +++ b/core/fpdfapi/parser/cpdf_data_avail.cpp
@@ -1,4 +1,4 @@ -// Copyright 2016 PDFium Authors. All rights reserved. +// Copyright 2016 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -24,32 +24,31 @@ #include "core/fpdfapi/parser/cpdf_stream.h" #include "core/fpdfapi/parser/cpdf_syntax_parser.h" #include "core/fpdfapi/parser/fpdf_parser_utility.h" +#include "core/fxcrt/autorestorer.h" #include "core/fxcrt/fx_extension.h" #include "core/fxcrt/fx_safe_types.h" -#include "third_party/base/compiler_specific.h" +#include "core/fxcrt/stl_util.h" +#include "third_party/base/check.h" +#include "third_party/base/containers/contains.h" +#include "third_party/base/notreached.h" #include "third_party/base/numerics/safe_conversions.h" -#include "third_party/base/ptr_util.h" -#include "third_party/base/stl_util.h" namespace { -// static -CPDF_Object* GetResourceObject(CPDF_Dictionary* pDict) { +RetainPtr<CPDF_Object> GetResourceObject(RetainPtr<CPDF_Dictionary> pDict) { constexpr size_t kMaxHierarchyDepth = 64; size_t depth = 0; - CPDF_Dictionary* dictionary_to_check = pDict; - while (dictionary_to_check) { - CPDF_Object* result = dictionary_to_check->GetObjectFor("Resources"); + while (pDict) { + RetainPtr<CPDF_Object> result = pDict->GetMutableObjectFor("Resources"); if (result) return result; - CPDF_Object* parent = dictionary_to_check->GetObjectFor("Parent"); - dictionary_to_check = parent ? parent->GetDict() : nullptr; - if (++depth > kMaxHierarchyDepth) { // We have cycle in parents hierarchy. return nullptr; } + RetainPtr<CPDF_Object> parent = pDict->GetMutableObjectFor("Parent"); + pDict = parent ? parent->GetMutableDict() : nullptr; } return nullptr; } @@ -59,7 +58,7 @@ HintsScope(RetainPtr<CPDF_ReadValidator> validator, CPDF_DataAvail::DownloadHints* hints) : validator_(std::move(validator)) { - ASSERT(validator_); + DCHECK(validator_); validator_->SetDownloadHints(hints); } @@ -71,18 +70,15 @@ } // namespace -CPDF_DataAvail::FileAvail::~FileAvail() {} +CPDF_DataAvail::FileAvail::~FileAvail() = default; -CPDF_DataAvail::DownloadHints::~DownloadHints() {} +CPDF_DataAvail::DownloadHints::~DownloadHints() = default; -CPDF_DataAvail::CPDF_DataAvail( - FileAvail* pFileAvail, - const RetainPtr<IFX_SeekableReadStream>& pFileRead, - bool bSupportHintTable) - : m_pFileRead( - pdfium::MakeRetain<CPDF_ReadValidator>(pFileRead, pFileAvail)), - m_dwFileLen(m_pFileRead->GetSize()), - m_bSupportHintTable(bSupportHintTable) {} +CPDF_DataAvail::CPDF_DataAvail(FileAvail* pFileAvail, + RetainPtr<IFX_SeekableReadStream> pFileRead) + : m_pFileRead(pdfium::MakeRetain<CPDF_ReadValidator>(std::move(pFileRead), + pFileAvail)), + m_dwFileLen(m_pFileRead->GetSize()) {} CPDF_DataAvail::~CPDF_DataAvail() { m_pHintTables.reset(); @@ -101,47 +97,49 @@ CPDF_DataAvail::DocAvailStatus CPDF_DataAvail::IsDocAvail( DownloadHints* pHints) { if (!m_dwFileLen) - return DataError; + return kDataError; + DCHECK(m_SeenPageObjList.empty()); + AutoRestorer<std::set<uint32_t>> seen_objects_restorer(&m_SeenPageObjList); const HintsScope hints_scope(GetValidator(), pHints); while (!m_bDocAvail) { if (!CheckDocStatus()) - return DataNotAvailable; + return kDataNotAvailable; } - return DataAvailable; + return kDataAvailable; } bool CPDF_DataAvail::CheckDocStatus() { - switch (m_docStatus) { - case PDF_DATAAVAIL_HEADER: + switch (m_internalStatus) { + case InternalStatus::kHeader: return CheckHeader(); - case PDF_DATAAVAIL_FIRSTPAGE: + case InternalStatus::kFirstPage: return CheckFirstPage(); - case PDF_DATAAVAIL_HINTTABLE: + case InternalStatus::kHintTable: return CheckHintTables(); - case PDF_DATAAVAIL_LOADALLCROSSREF: + case InternalStatus::kLoadAllCrossRef: return CheckAndLoadAllXref(); - case PDF_DATAAVAIL_LOADALLFILE: + case InternalStatus::kLoadAllFile: return LoadAllFile(); - case PDF_DATAAVAIL_ROOT: + case InternalStatus::kRoot: return CheckRoot(); - case PDF_DATAAVAIL_INFO: + case InternalStatus::kInfo: return CheckInfo(); - case PDF_DATAAVAIL_PAGETREE: + case InternalStatus::kPageTree: if (m_bTotalLoadPageTree) return CheckPages(); return LoadDocPages(); - case PDF_DATAAVAIL_PAGE: + case InternalStatus::kPage: if (m_bTotalLoadPageTree) return CheckPage(); - m_docStatus = PDF_DATAAVAIL_PAGE_LATERLOAD; + m_internalStatus = InternalStatus::kPageLaterLoad; return true; - case PDF_DATAAVAIL_ERROR: + case InternalStatus::kError: return LoadAllFile(); - case PDF_DATAAVAIL_PAGE_LATERLOAD: - m_docStatus = PDF_DATAAVAIL_PAGE; - FALLTHROUGH; + case InternalStatus::kPageLaterLoad: + m_internalStatus = InternalStatus::kPage; + [[fallthrough]]; default: m_bDocAvail = true; return true; @@ -149,12 +147,12 @@ } bool CPDF_DataAvail::CheckPageStatus() { - switch (m_docStatus) { - case PDF_DATAAVAIL_PAGETREE: + switch (m_internalStatus) { + case InternalStatus::kPageTree: return CheckPages(); - case PDF_DATAAVAIL_PAGE: + case InternalStatus::kPage: return CheckPage(); - case PDF_DATAAVAIL_ERROR: + case InternalStatus::kError: return LoadAllFile(); default: m_bPagesTreeLoad = true; @@ -165,7 +163,7 @@ bool CPDF_DataAvail::LoadAllFile() { if (GetValidator()->CheckWholeFileAndRequestIfUnavailable()) { - m_docStatus = PDF_DATAAVAIL_DONE; + m_internalStatus = InternalStatus::kDone; return true; } return false; @@ -173,27 +171,27 @@ bool CPDF_DataAvail::CheckAndLoadAllXref() { if (!m_pCrossRefAvail) { - const CPDF_ReadValidator::Session read_session(GetValidator()); + CPDF_ReadValidator::ScopedSession read_session(GetValidator()); const FX_FILESIZE last_xref_offset = m_parser.ParseStartXRef(); if (GetValidator()->has_read_problems()) return false; if (last_xref_offset <= 0) { - m_docStatus = PDF_DATAAVAIL_ERROR; + m_internalStatus = InternalStatus::kError; return false; } - m_pCrossRefAvail = pdfium::MakeUnique<CPDF_CrossRefAvail>(GetSyntaxParser(), - last_xref_offset); + m_pCrossRefAvail = std::make_unique<CPDF_CrossRefAvail>(GetSyntaxParser(), + last_xref_offset); } switch (m_pCrossRefAvail->CheckAvail()) { - case DocAvailStatus::DataAvailable: + case kDataAvailable: break; - case DocAvailStatus::DataNotAvailable: + case kDataNotAvailable: return false; - case DocAvailStatus::DataError: - m_docStatus = PDF_DATAAVAIL_ERROR; + case kDataError: + m_internalStatus = InternalStatus::kError; return false; default: NOTREACHED(); @@ -202,33 +200,29 @@ if (!m_parser.LoadAllCrossRefV4(m_pCrossRefAvail->last_crossref_offset()) && !m_parser.LoadAllCrossRefV5(m_pCrossRefAvail->last_crossref_offset())) { - m_docStatus = PDF_DATAAVAIL_LOADALLFILE; + m_internalStatus = InternalStatus::kLoadAllFile; return false; } - m_docStatus = PDF_DATAAVAIL_ROOT; + m_internalStatus = InternalStatus::kRoot; return true; } RetainPtr<CPDF_Object> CPDF_DataAvail::GetObject(uint32_t objnum, bool* pExistInFile) { - CPDF_Parser* pParser = nullptr; + *pExistInFile = false; + CPDF_Parser* pParser = m_pDocument ? m_pDocument->GetParser() : &m_parser; + if (!pParser) + return nullptr; - if (pExistInFile) - *pExistInFile = true; + CPDF_ReadValidator::ScopedSession read_session(GetValidator()); + RetainPtr<CPDF_Object> pRet = pParser->ParseIndirectObject(objnum); + if (!pRet) + return nullptr; - pParser = m_pDocument ? m_pDocument->GetParser() : &m_parser; - - RetainPtr<CPDF_Object> pRet; - if (pParser) { - const CPDF_ReadValidator::Session read_session(GetValidator()); - pRet = pParser->ParseIndirectObject(objnum); - if (GetValidator()->has_read_problems()) - return nullptr; - } - - if (!pRet && pExistInFile) - *pExistInFile = false; + *pExistInFile = true; + if (GetValidator()->has_read_problems()) + return nullptr; return pRet; } @@ -236,54 +230,64 @@ bool CPDF_DataAvail::CheckInfo() { const uint32_t dwInfoObjNum = m_parser.GetInfoObjNum(); if (dwInfoObjNum == CPDF_Object::kInvalidObjNum) { - m_docStatus = PDF_DATAAVAIL_PAGETREE; + m_internalStatus = InternalStatus::kPageTree; return true; } - const CPDF_ReadValidator::Session read_session(GetValidator()); + CPDF_ReadValidator::ScopedSession read_session(GetValidator()); m_parser.ParseIndirectObject(dwInfoObjNum); if (GetValidator()->has_read_problems()) return false; - m_docStatus = PDF_DATAAVAIL_PAGETREE; + m_internalStatus = InternalStatus::kPageTree; return true; } bool CPDF_DataAvail::CheckRoot() { const uint32_t dwRootObjNum = m_parser.GetRootObjNum(); if (dwRootObjNum == CPDF_Object::kInvalidObjNum) { - m_docStatus = PDF_DATAAVAIL_ERROR; + m_internalStatus = InternalStatus::kError; return true; } - const CPDF_ReadValidator::Session read_session(GetValidator()); + CPDF_ReadValidator::ScopedSession read_session(GetValidator()); m_pRoot = ToDictionary(m_parser.ParseIndirectObject(dwRootObjNum)); if (GetValidator()->has_read_problems()) return false; - const CPDF_Reference* pRef = - ToReference(m_pRoot ? m_pRoot->GetObjectFor("Pages") : nullptr); + if (!m_pRoot) { + m_internalStatus = InternalStatus::kError; + return false; + } + + RetainPtr<const CPDF_Reference> pRef = + ToReference(m_pRoot->GetObjectFor("Pages")); if (!pRef) { - m_docStatus = PDF_DATAAVAIL_ERROR; + m_internalStatus = InternalStatus::kError; return false; } m_PagesObjNum = pRef->GetRefObjNum(); - m_docStatus = PDF_DATAAVAIL_INFO; + m_internalStatus = InternalStatus::kInfo; return true; } bool CPDF_DataAvail::PreparePageItem() { const CPDF_Dictionary* pRoot = m_pDocument->GetRoot(); - const CPDF_Reference* pRef = - ToReference(pRoot ? pRoot->GetObjectFor("Pages") : nullptr); + if (!pRoot) { + m_internalStatus = InternalStatus::kError; + return false; + } + + RetainPtr<const CPDF_Reference> pRef = + ToReference(pRoot->GetObjectFor("Pages")); if (!pRef) { - m_docStatus = PDF_DATAAVAIL_ERROR; + m_internalStatus = InternalStatus::kError; return false; } m_PagesObjNum = pRef->GetRefObjNum(); - m_docStatus = PDF_DATAAVAIL_PAGETREE; + m_internalStatus = InternalStatus::kPageTree; return true; } @@ -305,21 +309,23 @@ UnavailObjList.push_back(dwPageObjNum); continue; } - CPDF_Array* pArray = ToArray(pObj.Get()); - if (pArray) { - CPDF_ArrayLocker locker(pArray); - for (const auto& pArrayObj : locker) { - if (CPDF_Reference* pRef = ToReference(pArrayObj.Get())) - UnavailObjList.push_back(pRef->GetRefObjNum()); - } - } - if (!pObj->IsDictionary()) - continue; - ByteString type = pObj->GetDict()->GetStringFor("Type"); - if (type == "Pages") { - m_PagesArray.push_back(std::move(pObj)); - continue; + switch (pObj->GetType()) { + case CPDF_Object::kArray: { + CPDF_ArrayLocker locker(pObj->AsArray()); + for (const auto& pArrayObj : locker) { + const CPDF_Reference* pRef = ToReference(pArrayObj.Get()); + if (pRef) + UnavailObjList.push_back(pRef->GetRefObjNum()); + } + break; + } + case CPDF_Object::kDictionary: + if (pObj->GetDict()->GetNameFor("Type") == "Pages") + m_PagesArray.push_back(std::move(pObj)); + break; + default: + break; } } m_PageObjList.clear(); @@ -332,39 +338,50 @@ RetainPtr<CPDF_Object> pPages = std::move(m_PagesArray[i]); if (pPages && !GetPageKids(pPages.Get())) { m_PagesArray.clear(); - m_docStatus = PDF_DATAAVAIL_ERROR; + m_internalStatus = InternalStatus::kError; return false; } } m_PagesArray.clear(); if (m_PageObjList.empty()) - m_docStatus = PDF_DATAAVAIL_DONE; + m_internalStatus = InternalStatus::kDone; return true; } bool CPDF_DataAvail::GetPageKids(CPDF_Object* pPages) { - CPDF_Dictionary* pDict = pPages->GetDict(); - CPDF_Object* pKids = pDict ? pDict->GetObjectFor("Kids") : nullptr; + RetainPtr<const CPDF_Dictionary> pDict = pPages->GetDict(); + if (!pDict) + return true; + + RetainPtr<const CPDF_Object> pKids = pDict->GetObjectFor("Kids"); if (!pKids) return true; + std::vector<uint32_t> object_numbers; switch (pKids->GetType()) { case CPDF_Object::kReference: - m_PageObjList.push_back(pKids->AsReference()->GetRefObjNum()); + object_numbers.push_back(pKids->AsReference()->GetRefObjNum()); break; case CPDF_Object::kArray: { - CPDF_Array* pKidsArray = pKids->AsArray(); - for (size_t i = 0; i < pKidsArray->size(); ++i) { - if (CPDF_Reference* pRef = ToReference(pKidsArray->GetObjectAt(i))) - m_PageObjList.push_back(pRef->GetRefObjNum()); + CPDF_ArrayLocker locker(pKids->AsArray()); + for (const auto& pArrayObj : locker) { + const CPDF_Reference* pRef = ToReference(pArrayObj.Get()); + if (pRef) + object_numbers.push_back(pRef->GetRefObjNum()); } break; } default: - m_docStatus = PDF_DATAAVAIL_ERROR; + m_internalStatus = InternalStatus::kError; return false; } + + for (uint32_t num : object_numbers) { + bool inserted = m_SeenPageObjList.insert(num).second; + if (inserted) + m_PageObjList.push_back(num); + } return true; } @@ -372,37 +389,37 @@ bool bExists = false; RetainPtr<CPDF_Object> pPages = GetObject(m_PagesObjNum, &bExists); if (!bExists) { - m_docStatus = PDF_DATAAVAIL_LOADALLFILE; + m_internalStatus = InternalStatus::kLoadAllFile; return true; } if (!pPages) { - if (m_docStatus == PDF_DATAAVAIL_ERROR) { - m_docStatus = PDF_DATAAVAIL_LOADALLFILE; + if (m_internalStatus == InternalStatus::kError) { + m_internalStatus = InternalStatus::kLoadAllFile; return true; } return false; } if (!GetPageKids(pPages.Get())) { - m_docStatus = PDF_DATAAVAIL_ERROR; + m_internalStatus = InternalStatus::kError; return false; } - m_docStatus = PDF_DATAAVAIL_PAGE; + m_internalStatus = InternalStatus::kPage; return true; } bool CPDF_DataAvail::CheckHeader() { switch (CheckHeaderAndLinearized()) { - case DocAvailStatus::DataAvailable: - m_docStatus = m_pLinearized ? PDF_DATAAVAIL_FIRSTPAGE - : PDF_DATAAVAIL_LOADALLCROSSREF; + case kDataAvailable: + m_internalStatus = m_pLinearized ? InternalStatus::kFirstPage + : InternalStatus::kLoadAllCrossRef; return true; - case DocAvailStatus::DataNotAvailable: + case kDataNotAvailable: return false; - case DocAvailStatus::DataError: - m_docStatus = PDF_DATAAVAIL_ERROR; + case kDataError: + m_internalStatus = InternalStatus::kError; return true; default: NOTREACHED(); @@ -414,7 +431,7 @@ if (!m_pLinearized->GetFirstPageEndOffset() || !m_pLinearized->GetFileSize() || !m_pLinearized->GetMainXRefTableFirstEntryOffset()) { - m_docStatus = PDF_DATAAVAIL_ERROR; + m_internalStatus = InternalStatus::kError; return false; } @@ -429,24 +446,23 @@ data_size)) return false; - m_docStatus = - m_bSupportHintTable ? PDF_DATAAVAIL_HINTTABLE : PDF_DATAAVAIL_DONE; + m_internalStatus = InternalStatus::kHintTable; return true; } bool CPDF_DataAvail::CheckHintTables() { - const CPDF_ReadValidator::Session read_session(GetValidator()); + CPDF_ReadValidator::ScopedSession read_session(GetValidator()); m_pHintTables = CPDF_HintTables::Parse(GetSyntaxParser(), m_pLinearized.get()); if (GetValidator()->read_error()) { - m_docStatus = PDF_DATAAVAIL_ERROR; + m_internalStatus = InternalStatus::kError; return true; } if (GetValidator()->has_unavailable_data()) return false; - m_docStatus = PDF_DATAAVAIL_DONE; + m_internalStatus = InternalStatus::kDone; return true; } @@ -466,59 +482,59 @@ CPDF_DataAvail::DocLinearizationStatus CPDF_DataAvail::IsLinearizedPDF() { switch (CheckHeaderAndLinearized()) { - case DocAvailStatus::DataAvailable: - return m_pLinearized ? DocLinearizationStatus::Linearized - : DocLinearizationStatus::NotLinearized; - case DocAvailStatus::DataNotAvailable: - return DocLinearizationStatus::LinearizationUnknown; - case DocAvailStatus::DataError: - return DocLinearizationStatus::NotLinearized; + case kDataAvailable: + return m_pLinearized ? kLinearized : kNotLinearized; + case kDataNotAvailable: + return kLinearizationUnknown; + case kDataError: + return kNotLinearized; default: NOTREACHED(); - return DocLinearizationStatus::LinearizationUnknown; + return kLinearizationUnknown; } } CPDF_DataAvail::DocAvailStatus CPDF_DataAvail::CheckHeaderAndLinearized() { if (m_bHeaderAvail) - return DocAvailStatus::DataAvailable; + return kDataAvailable; - const CPDF_ReadValidator::Session read_session(GetValidator()); - const Optional<FX_FILESIZE> header_offset = GetHeaderOffset(GetValidator()); + CPDF_ReadValidator::ScopedSession read_session(GetValidator()); + const absl::optional<FX_FILESIZE> header_offset = + GetHeaderOffset(GetValidator()); if (GetValidator()->has_read_problems()) - return DocAvailStatus::DataNotAvailable; + return kDataNotAvailable; - if (!header_offset) - return DocAvailStatus::DataError; + if (!header_offset.has_value()) + return kDataError; - m_parser.m_pSyntax = - pdfium::MakeUnique<CPDF_SyntaxParser>(GetValidator(), *header_offset); + m_parser.m_pSyntax = std::make_unique<CPDF_SyntaxParser>( + GetValidator(), header_offset.value()); m_pLinearized = m_parser.ParseLinearizedHeader(); if (GetValidator()->has_read_problems()) - return DocAvailStatus::DataNotAvailable; + return kDataNotAvailable; m_bHeaderAvail = true; - return DocAvailStatus::DataAvailable; + return kDataAvailable; } bool CPDF_DataAvail::CheckPage(uint32_t dwPage) { while (true) { - switch (m_docStatus) { - case PDF_DATAAVAIL_PAGETREE: + switch (m_internalStatus) { + case InternalStatus::kPageTree: if (!LoadDocPages()) return false; break; - case PDF_DATAAVAIL_PAGE: + case InternalStatus::kPage: if (!LoadDocPage(dwPage)) return false; break; - case PDF_DATAAVAIL_ERROR: + case InternalStatus::kError: return LoadAllFile(); default: m_bPagesTreeLoad = true; m_bPagesLoad = true; m_bCurPageDictLoadOK = true; - m_docStatus = PDF_DATAAVAIL_PAGE; + m_internalStatus = InternalStatus::kPage; return true; } } @@ -529,26 +545,26 @@ bool bExists = false; RetainPtr<CPDF_Object> pPages = GetObject(dwPageNo, &bExists); if (!bExists) { - m_docStatus = PDF_DATAAVAIL_ERROR; + m_internalStatus = InternalStatus::kError; return false; } if (!pPages) return false; - CPDF_Array* pArray = pPages->AsArray(); + const CPDF_Array* pArray = pPages->AsArray(); if (!pArray) { - m_docStatus = PDF_DATAAVAIL_ERROR; + m_internalStatus = InternalStatus::kError; return false; } - pPageNode->m_type = PDF_PAGENODE_PAGES; + pPageNode->m_type = PageNode::Type::kPages; for (size_t i = 0; i < pArray->size(); ++i) { - CPDF_Reference* pKid = ToReference(pArray->GetObjectAt(i)); + RetainPtr<const CPDF_Reference> pKid = ToReference(pArray->GetObjectAt(i)); if (!pKid) continue; - auto pNode = pdfium::MakeUnique<PageNode>(); + auto pNode = std::make_unique<PageNode>(); pNode->m_dwPageNo = pKid->GetRefObjNum(); pPageNode->m_ChildNodes.push_back(std::move(pNode)); } @@ -560,7 +576,7 @@ bool bExists = false; RetainPtr<CPDF_Object> pPage = GetObject(dwPageNo, &bExists); if (!bExists) { - m_docStatus = PDF_DATAAVAIL_ERROR; + m_internalStatus = InternalStatus::kError; return false; } @@ -569,51 +585,52 @@ if (pPage->IsArray()) { pPageNode->m_dwPageNo = dwPageNo; - pPageNode->m_type = PDF_PAGENODE_ARRAY; + pPageNode->m_type = PageNode::Type::kArray; return true; } if (!pPage->IsDictionary()) { - m_docStatus = PDF_DATAAVAIL_ERROR; + m_internalStatus = InternalStatus::kError; return false; } pPageNode->m_dwPageNo = dwPageNo; - CPDF_Dictionary* pDict = pPage->GetDict(); - const ByteString type = pDict->GetStringFor("Type"); + RetainPtr<CPDF_Dictionary> pDict = pPage->GetMutableDict(); + const ByteString type = pDict->GetNameFor("Type"); if (type == "Page") { - pPageNode->m_type = PDF_PAGENODE_PAGE; + pPageNode->m_type = PageNode::Type::kPage; return true; } if (type != "Pages") { - m_docStatus = PDF_DATAAVAIL_ERROR; + m_internalStatus = InternalStatus::kError; return false; } - pPageNode->m_type = PDF_PAGENODE_PAGES; - CPDF_Object* pKids = pDict->GetObjectFor("Kids"); + pPageNode->m_type = PageNode::Type::kPages; + RetainPtr<CPDF_Object> pKids = pDict->GetMutableObjectFor("Kids"); if (!pKids) { - m_docStatus = PDF_DATAAVAIL_PAGE; + m_internalStatus = InternalStatus::kPage; return true; } switch (pKids->GetType()) { case CPDF_Object::kReference: { - CPDF_Reference* pKid = pKids->AsReference(); - auto pNode = pdfium::MakeUnique<PageNode>(); + const CPDF_Reference* pKid = pKids->AsReference(); + auto pNode = std::make_unique<PageNode>(); pNode->m_dwPageNo = pKid->GetRefObjNum(); pPageNode->m_ChildNodes.push_back(std::move(pNode)); break; } case CPDF_Object::kArray: { - CPDF_Array* pKidsArray = pKids->AsArray(); + const CPDF_Array* pKidsArray = pKids->AsArray(); for (size_t i = 0; i < pKidsArray->size(); ++i) { - CPDF_Reference* pKid = ToReference(pKidsArray->GetObjectAt(i)); + RetainPtr<const CPDF_Reference> pKid = + ToReference(pKidsArray->GetObjectAt(i)); if (!pKid) continue; - auto pNode = pdfium::MakeUnique<PageNode>(); + auto pNode = std::make_unique<PageNode>(); pNode->m_dwPageNo = pKid->GetRefObjNum(); pPageNode->m_ChildNodes.push_back(std::move(pNode)); } @@ -632,9 +649,9 @@ if (level >= kMaxPageRecursionDepth) return false; - int32_t iSize = pdfium::CollectionSize<int32_t>(pageNode.m_ChildNodes); + int32_t iSize = fxcrt::CollectionSize<int32_t>(pageNode.m_ChildNodes); if (iSize <= 0 || iPage >= iSize) { - m_docStatus = PDF_DATAAVAIL_ERROR; + m_internalStatus = InternalStatus::kError; return false; } for (int32_t i = 0; i < iSize; ++i) { @@ -642,33 +659,33 @@ if (!pNode) continue; - if (pNode->m_type == PDF_PAGENODE_UNKNOWN) { + if (pNode->m_type == PageNode::Type::kUnknown) { // Updates the type for the unknown page node. if (!CheckUnknownPageNode(pNode->m_dwPageNo, pNode)) return false; } - if (pNode->m_type == PDF_PAGENODE_ARRAY) { + if (pNode->m_type == PageNode::Type::kArray) { // Updates a more specific type for the array page node. if (!CheckArrayPageNode(pNode->m_dwPageNo, pNode)) return false; } switch (pNode->m_type) { - case PDF_PAGENODE_PAGE: + case PageNode::Type::kPage: iCount++; if (iPage == iCount && m_pDocument) m_pDocument->SetPageObjNum(iPage, pNode->m_dwPageNo); break; - case PDF_PAGENODE_PAGES: + case PageNode::Type::kPages: if (!CheckPageNode(*pNode, iPage, iCount, level + 1)) return false; break; - case PDF_PAGENODE_UNKNOWN: - case PDF_PAGENODE_ARRAY: + case PageNode::Type::kUnknown: + case PageNode::Type::kArray: // Already converted above, error if we get here. return false; } if (iPage == iCount) { - m_docStatus = PDF_DATAAVAIL_DONE; + m_internalStatus = InternalStatus::kDone; return true; } } @@ -676,15 +693,15 @@ } bool CPDF_DataAvail::LoadDocPage(uint32_t dwPage) { - FX_SAFE_INT32 safePage = pdfium::base::checked_cast<int32_t>(dwPage); - int32_t iPage = safePage.ValueOrDie(); + int iPage = pdfium::base::checked_cast<int>(dwPage); if (m_pDocument->GetPageCount() <= iPage || m_pDocument->IsPageLoaded(iPage)) { - m_docStatus = PDF_DATAAVAIL_DONE; + m_internalStatus = InternalStatus::kDone; return true; } - if (m_PageNode.m_type == PDF_PAGENODE_PAGE) { - m_docStatus = iPage == 0 ? PDF_DATAAVAIL_DONE : PDF_DATAAVAIL_ERROR; + if (m_PageNode.m_type == PageNode::Type::kPage) { + m_internalStatus = + iPage == 0 ? InternalStatus::kDone : InternalStatus::kError; return true; } int32_t iCount = -1; @@ -695,15 +712,15 @@ bool bExists = false; RetainPtr<CPDF_Object> pPages = GetObject(m_PagesObjNum, &bExists); if (!bExists) { - m_docStatus = PDF_DATAAVAIL_ERROR; + m_internalStatus = InternalStatus::kError; return false; } if (!pPages) return false; - CPDF_Dictionary* pPagesDict = pPages->GetDict(); + RetainPtr<const CPDF_Dictionary> pPagesDict = pPages->GetDict(); if (!pPagesDict) { - m_docStatus = PDF_DATAAVAIL_ERROR; + m_internalStatus = InternalStatus::kError; return false; } if (!pPagesDict->KeyExist("Kids")) @@ -717,7 +734,7 @@ return false; if (CheckPageCount()) { - m_docStatus = PDF_DATAAVAIL_PAGE; + m_internalStatus = InternalStatus::kPage; return true; } @@ -740,11 +757,11 @@ CPDF_DataAvail::DocAvailStatus CPDF_DataAvail::CheckLinearizedData() { if (m_bLinearedDataOK) - return DataAvailable; - ASSERT(m_pLinearized); + return kDataAvailable; + DCHECK(m_pLinearized); if (!m_pLinearized->GetMainXRefTableFirstEntryOffset() || !m_pDocument || !m_pDocument->GetParser() || !m_pDocument->GetParser()->GetTrailer()) { - return DataError; + return kDataError; } if (!m_bMainXRefLoadTried) { @@ -752,68 +769,66 @@ m_pDocument->GetParser()->GetTrailer()->GetIntegerFor("Prev"); const FX_FILESIZE main_xref_offset = prev.ValueOrDefault(-1); if (main_xref_offset < 0) - return DataError; + return kDataError; if (main_xref_offset == 0) - return DataAvailable; + return kDataAvailable; FX_SAFE_SIZE_T data_size = m_dwFileLen; data_size -= main_xref_offset; if (!data_size.IsValid()) - return DataError; + return kDataError; if (!GetValidator()->CheckDataRangeAndRequestIfUnavailable( main_xref_offset, data_size.ValueOrDie())) - return DataNotAvailable; + return kDataNotAvailable; CPDF_Parser::Error eRet = m_pDocument->GetParser()->LoadLinearizedMainXRefTable(); m_bMainXRefLoadTried = true; if (eRet != CPDF_Parser::SUCCESS) - return DataError; + return kDataError; if (!PreparePageItem()) - return DataNotAvailable; + return kDataNotAvailable; m_bMainXRefLoadedOK = true; m_bLinearedDataOK = true; } - return m_bLinearedDataOK ? DataAvailable : DataNotAvailable; + return m_bLinearedDataOK ? kDataAvailable : kDataNotAvailable; } CPDF_DataAvail::DocAvailStatus CPDF_DataAvail::IsPageAvail( uint32_t dwPage, DownloadHints* pHints) { if (!m_pDocument) - return DataError; + return kDataError; - const FX_SAFE_INT32 safePage = pdfium::base::checked_cast<int32_t>(dwPage); - if (!safePage.IsValid()) - return DataError; - - if (safePage.ValueOrDie() >= m_pDocument->GetPageCount()) { + const int iPage = pdfium::base::checked_cast<int>(dwPage); + if (iPage >= m_pDocument->GetPageCount()) { // This is XFA page. - return DataAvailable; + return kDataAvailable; } if (IsFirstCheck(dwPage)) { m_bCurPageDictLoadOK = false; } - if (pdfium::ContainsKey(m_pagesLoadState, dwPage)) - return DataAvailable; + if (pdfium::Contains(m_pagesLoadState, dwPage)) + return kDataAvailable; const HintsScope hints_scope(GetValidator(), pHints); if (m_pLinearized) { if (dwPage == m_pLinearized->GetFirstPageNo()) { - auto* pPageDict = m_pDocument->GetPageDictionary(safePage.ValueOrDie()); + RetainPtr<const CPDF_Dictionary> pPageDict = + m_pDocument->GetPageDictionary(iPage); if (!pPageDict) - return DataError; + return kDataError; - auto page_num_obj = std::make_pair( - dwPage, pdfium::MakeUnique<CPDF_PageObjectAvail>( - GetValidator(), m_pDocument.Get(), pPageDict)); + auto page_num_obj = + std::make_pair(dwPage, std::make_unique<CPDF_PageObjectAvail>( + GetValidator(), m_pDocument, pPageDict)); CPDF_PageObjectAvail* page_obj_avail = m_PagesObjAvail.insert(std::move(page_num_obj)).first->second.get(); @@ -822,83 +837,84 @@ } DocAvailStatus nResult = CheckLinearizedData(); - if (nResult != DataAvailable) + if (nResult != kDataAvailable) return nResult; if (m_pHintTables) { nResult = m_pHintTables->CheckPage(dwPage); - if (nResult != DataAvailable) + if (nResult != kDataAvailable) return nResult; if (GetPageDictionary(dwPage)) { m_pagesLoadState.insert(dwPage); - return DataAvailable; + return kDataAvailable; } } if (!m_bMainXRefLoadedOK) { if (!LoadAllFile()) - return DataNotAvailable; + return kDataNotAvailable; m_pDocument->GetParser()->RebuildCrossRef(); ResetFirstCheck(dwPage); - return DataAvailable; + return kDataAvailable; } if (m_bTotalLoadPageTree) { if (!LoadPages()) - return DataNotAvailable; + return kDataNotAvailable; } else { if (!m_bCurPageDictLoadOK && !CheckPage(dwPage)) - return DataNotAvailable; + return kDataNotAvailable; } } else { if (!m_bTotalLoadPageTree && !m_bCurPageDictLoadOK && !CheckPage(dwPage)) { - return DataNotAvailable; + return kDataNotAvailable; } } - if (CheckAcroForm() == DocFormStatus::FormNotAvailable) - return DataNotAvailable; + if (CheckAcroForm() == kFormNotAvailable) + return kDataNotAvailable; - auto* pPageDict = m_pDocument->GetPageDictionary(safePage.ValueOrDie()); + RetainPtr<CPDF_Dictionary> pPageDict = + m_pDocument->GetMutablePageDictionary(iPage); if (!pPageDict) - return DataError; + return kDataError; { - auto page_num_obj = std::make_pair( - dwPage, pdfium::MakeUnique<CPDF_PageObjectAvail>( - GetValidator(), m_pDocument.Get(), pPageDict)); + auto page_num_obj = + std::make_pair(dwPage, std::make_unique<CPDF_PageObjectAvail>( + GetValidator(), m_pDocument, pPageDict)); CPDF_PageObjectAvail* page_obj_avail = m_PagesObjAvail.insert(std::move(page_num_obj)).first->second.get(); const DocAvailStatus status = page_obj_avail->CheckAvail(); - if (status != DocAvailStatus::DataAvailable) + if (status != kDataAvailable) return status; } - const DocAvailStatus resources_status = CheckResources(pPageDict); - if (resources_status != DocAvailStatus::DataAvailable) + const DocAvailStatus resources_status = CheckResources(std::move(pPageDict)); + if (resources_status != kDataAvailable) return resources_status; m_bCurPageDictLoadOK = false; ResetFirstCheck(dwPage); m_pagesLoadState.insert(dwPage); - return DataAvailable; + return kDataAvailable; } CPDF_DataAvail::DocAvailStatus CPDF_DataAvail::CheckResources( - CPDF_Dictionary* page) { - ASSERT(page); - const CPDF_ReadValidator::Session read_session(GetValidator()); - CPDF_Object* resources = GetResourceObject(page); + RetainPtr<CPDF_Dictionary> page) { + DCHECK(page); + CPDF_ReadValidator::ScopedSession read_session(GetValidator()); + RetainPtr<CPDF_Object> resources = GetResourceObject(std::move(page)); if (GetValidator()->has_read_problems()) - return DocAvailStatus::DataNotAvailable; + return kDataNotAvailable; if (!resources) - return DocAvailStatus::DataAvailable; + return kDataAvailable; CPDF_PageObjectAvail* resource_avail = m_PagesResourcesAvail - .insert(std::make_pair( - resources, pdfium::MakeUnique<CPDF_PageObjectAvail>( - GetValidator(), m_pDocument.Get(), resources))) + .insert(std::make_pair(resources, + std::make_unique<CPDF_PageObjectAvail>( + GetValidator(), m_pDocument, resources))) .first->second.get(); return resource_avail->CheckAvail(); } @@ -918,10 +934,11 @@ return m_pDocument ? m_pDocument->GetPageCount() : 0; } -CPDF_Dictionary* CPDF_DataAvail::GetPageDictionary(int index) const { +RetainPtr<const CPDF_Dictionary> CPDF_DataAvail::GetPageDictionary( + int index) const { if (!m_pDocument || index < 0 || index >= GetPageCount()) return nullptr; - CPDF_Dictionary* page = m_pDocument->GetPageDictionary(index); + RetainPtr<const CPDF_Dictionary> page = m_pDocument->GetPageDictionary(index); if (page) return page; if (!m_pLinearized || !m_pHintTables) @@ -941,8 +958,7 @@ // Page object already can be parsed in document. if (!m_pDocument->GetIndirectObject(dwObjNum)) { m_pDocument->ReplaceIndirectObjectIfHigherGeneration( - dwObjNum, - ParseIndirectObjectAt(szPageStartPos, dwObjNum, m_pDocument.Get())); + dwObjNum, ParseIndirectObjectAt(szPageStartPos, dwObjNum, m_pDocument)); } if (!ValidatePage(index)) return nullptr; @@ -957,64 +973,67 @@ CPDF_DataAvail::DocFormStatus CPDF_DataAvail::CheckAcroForm() { if (!m_pDocument) - return FormAvailable; + return kFormAvailable; if (m_pLinearized) { DocAvailStatus nDocStatus = CheckLinearizedData(); - if (nDocStatus == DataError) - return FormError; - if (nDocStatus == DataNotAvailable) - return FormNotAvailable; + if (nDocStatus == kDataError) + return kFormError; + if (nDocStatus == kDataNotAvailable) + return kFormNotAvailable; } if (!m_pFormAvail) { - CPDF_Dictionary* pRoot = m_pDocument->GetRoot(); + const CPDF_Dictionary* pRoot = m_pDocument->GetRoot(); if (!pRoot) - return FormAvailable; + return kFormAvailable; - CPDF_Object* pAcroForm = pRoot->GetObjectFor("AcroForm"); + RetainPtr<const CPDF_Object> pAcroForm = pRoot->GetObjectFor("AcroForm"); if (!pAcroForm) - return FormNotExist; + return kFormNotExist; - m_pFormAvail = pdfium::MakeUnique<CPDF_PageObjectAvail>( - GetValidator(), m_pDocument.Get(), pAcroForm); + m_pFormAvail = std::make_unique<CPDF_PageObjectAvail>( + GetValidator(), m_pDocument, std::move(pAcroForm)); } switch (m_pFormAvail->CheckAvail()) { - case DocAvailStatus::DataError: - return DocFormStatus::FormError; - case DocAvailStatus::DataNotAvailable: - return DocFormStatus::FormNotAvailable; - case DocAvailStatus::DataAvailable: - return DocFormStatus::FormAvailable; + case kDataError: + return kFormError; + case kDataNotAvailable: + return kFormNotAvailable; + case kDataAvailable: + return kFormAvailable; default: NOTREACHED(); } - return DocFormStatus::FormError; + return kFormError; } bool CPDF_DataAvail::ValidatePage(uint32_t dwPage) const { - FX_SAFE_INT32 safePage = pdfium::base::checked_cast<int32_t>(dwPage); - auto* pPageDict = m_pDocument->GetPageDictionary(safePage.ValueOrDie()); + int iPage = pdfium::base::checked_cast<int>(dwPage); + RetainPtr<const CPDF_Dictionary> pPageDict = + m_pDocument->GetPageDictionary(iPage); if (!pPageDict) return false; - CPDF_PageObjectAvail obj_avail(GetValidator(), m_pDocument.Get(), pPageDict); - return obj_avail.CheckAvail() == DocAvailStatus::DataAvailable; + + CPDF_PageObjectAvail obj_avail(GetValidator(), m_pDocument, + std::move(pPageDict)); + return obj_avail.CheckAvail() == kDataAvailable; } std::pair<CPDF_Parser::Error, std::unique_ptr<CPDF_Document>> CPDF_DataAvail::ParseDocument( std::unique_ptr<CPDF_Document::RenderDataIface> pRenderData, std::unique_ptr<CPDF_Document::PageDataIface> pPageData, - const char* password) { + const ByteString& password) { if (m_pDocument) { // We already returned parsed document. return std::make_pair(CPDF_Parser::HANDLER_ERROR, nullptr); } - auto document = pdfium::MakeUnique<CPDF_Document>(std::move(pRenderData), - std::move(pPageData)); + auto document = std::make_unique<CPDF_Document>(std::move(pRenderData), + std::move(pPageData)); document->AddObserver(this); - CPDF_ReadValidator::Session read_session(GetValidator()); + CPDF_ReadValidator::ScopedSession read_session(GetValidator()); CPDF_Parser::Error error = document->LoadLinearizedDoc(GetValidator(), password); @@ -1031,6 +1050,6 @@ return std::make_pair(CPDF_Parser::SUCCESS, std::move(document)); } -CPDF_DataAvail::PageNode::PageNode() : m_type(PDF_PAGENODE_UNKNOWN) {} +CPDF_DataAvail::PageNode::PageNode() = default; -CPDF_DataAvail::PageNode::~PageNode() {} +CPDF_DataAvail::PageNode::~PageNode() = default;
diff --git a/core/fpdfapi/parser/cpdf_data_avail.h b/core/fpdfapi/parser/cpdf_data_avail.h index 6bcea07..a3f215e 100644 --- a/core/fpdfapi/parser/cpdf_data_avail.h +++ b/core/fpdfapi/parser/cpdf_data_avail.h
@@ -1,4 +1,4 @@ -// Copyright 2016 PDFium Authors. All rights reserved. +// Copyright 2016 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -7,6 +7,7 @@ #ifndef CORE_FPDFAPI_PARSER_CPDF_DATA_AVAIL_H_ #define CORE_FPDFAPI_PARSER_CPDF_DATA_AVAIL_H_ +#include <functional> #include <map> #include <memory> #include <set> @@ -15,6 +16,7 @@ #include "core/fpdfapi/parser/cpdf_document.h" #include "core/fpdfapi/parser/cpdf_parser.h" +#include "core/fxcrt/retain_ptr.h" #include "core/fxcrt/unowned_ptr.h" class CPDF_CrossRefAvail; @@ -26,57 +28,34 @@ class CPDF_ReadValidator; class CPDF_SyntaxParser; -enum PDF_DATAAVAIL_STATUS { - PDF_DATAAVAIL_HEADER = 0, - PDF_DATAAVAIL_FIRSTPAGE, - PDF_DATAAVAIL_HINTTABLE, - PDF_DATAAVAIL_LOADALLCROSSREF, - PDF_DATAAVAIL_ROOT, - PDF_DATAAVAIL_INFO, - PDF_DATAAVAIL_PAGETREE, - PDF_DATAAVAIL_PAGE, - PDF_DATAAVAIL_PAGE_LATERLOAD, - PDF_DATAAVAIL_RESOURCES, - PDF_DATAAVAIL_DONE, - PDF_DATAAVAIL_ERROR, - PDF_DATAAVAIL_LOADALLFILE, -}; - -enum PDF_PAGENODE_TYPE { - PDF_PAGENODE_UNKNOWN = 0, - PDF_PAGENODE_PAGE, - PDF_PAGENODE_PAGES, - PDF_PAGENODE_ARRAY, -}; - class CPDF_DataAvail final : public Observable::ObserverIface { public: // Must match PDF_DATA_* definitions in public/fpdf_dataavail.h, but cannot // #include that header. fpdfsdk/fpdf_dataavail.cpp has static_asserts // to make sure the two sets of values match. enum DocAvailStatus { - DataError = -1, // PDF_DATA_ERROR - DataNotAvailable = 0, // PDF_DATA_NOTAVAIL - DataAvailable = 1, // PDF_DATA_AVAIL + kDataError = -1, // PDF_DATA_ERROR + kDataNotAvailable = 0, // PDF_DATA_NOTAVAIL + kDataAvailable = 1, // PDF_DATA_AVAIL }; // Must match PDF_*LINEAR* definitions in public/fpdf_dataavail.h, but cannot // #include that header. fpdfsdk/fpdf_dataavail.cpp has static_asserts // to make sure the two sets of values match. enum DocLinearizationStatus { - LinearizationUnknown = -1, // PDF_LINEARIZATION_UNKNOWN - NotLinearized = 0, // PDF_NOT_LINEARIZED - Linearized = 1, // PDF_LINEARIZED + kLinearizationUnknown = -1, // PDF_LINEARIZATION_UNKNOWN + kNotLinearized = 0, // PDF_NOT_LINEARIZED + kLinearized = 1, // PDF_LINEARIZED }; // Must match PDF_FORM_* definitions in public/fpdf_dataavail.h, but cannot // #include that header. fpdfsdk/fpdf_dataavail.cpp has static_asserts // to make sure the two sets of values match. enum DocFormStatus { - FormError = -1, // PDF_FORM_ERROR - FormNotAvailable = 0, // PDF_FORM_NOTAVAIL - FormAvailable = 1, // PDF_FORM_AVAIL - FormNotExist = 2, // PDF_FORM_NOTEXIST + kFormError = -1, // PDF_FORM_ERROR + kFormNotAvailable = 0, // PDF_FORM_NOTAVAIL + kFormAvailable = 1, // PDF_FORM_AVAIL + kFormNotExist = 2, // PDF_FORM_NOTEXIST }; class FileAvail { @@ -92,11 +71,10 @@ }; CPDF_DataAvail(FileAvail* pFileAvail, - const RetainPtr<IFX_SeekableReadStream>& pFileRead, - bool bSupportHintTable); + RetainPtr<IFX_SeekableReadStream> pFileRead); ~CPDF_DataAvail() override; - // CPDF_Document::Observer: + // Observable::ObserverIface: void OnObservableDestroyed() override; DocAvailStatus IsDocAvail(DownloadHints* pHints); @@ -104,28 +82,48 @@ DocFormStatus IsFormAvail(DownloadHints* pHints); DocLinearizationStatus IsLinearizedPDF(); int GetPageCount() const; - CPDF_Dictionary* GetPageDictionary(int index) const; + RetainPtr<const CPDF_Dictionary> GetPageDictionary(int index) const; RetainPtr<CPDF_ReadValidator> GetValidator() const; std::pair<CPDF_Parser::Error, std::unique_ptr<CPDF_Document>> ParseDocument( std::unique_ptr<CPDF_Document::RenderDataIface> pRenderData, std::unique_ptr<CPDF_Document::PageDataIface> pPageData, - const char* password); + const ByteString& password); - const CPDF_HintTables* GetHintTables() const { return m_pHintTables.get(); } + const CPDF_HintTables* GetHintTablesForTest() const { + return m_pHintTables.get(); + } private: + enum class InternalStatus : uint8_t { + kHeader = 0, + kFirstPage, + kHintTable, + kLoadAllCrossRef, + kRoot, + kInfo, + kPageTree, + kPage, + kPageLaterLoad, + kResources, + kDone, + kError, + kLoadAllFile, + }; + class PageNode { public: + enum class Type { kUnknown = 0, kPage, kPages, kArray }; + PageNode(); ~PageNode(); - PDF_PAGENODE_TYPE m_type; - uint32_t m_dwPageNo; + Type m_type = Type::kUnknown; + uint32_t m_dwPageNo = 0; std::vector<std::unique_ptr<PageNode>> m_ChildNodes; }; - static const int kMaxPageRecursionDepth = 1024; + static constexpr int kMaxPageRecursionDepth = 1024; bool CheckDocStatus(); bool CheckHeader(); @@ -135,7 +133,7 @@ bool CheckInfo(); bool CheckPages(); bool CheckPage(); - DocAvailStatus CheckResources(CPDF_Dictionary* page); + DocAvailStatus CheckResources(RetainPtr<CPDF_Dictionary> page); DocFormStatus CheckAcroForm(); bool CheckPageStatus(); @@ -172,11 +170,12 @@ RetainPtr<CPDF_Dictionary> m_pRoot; std::unique_ptr<CPDF_LinearizedHeader> m_pLinearized; bool m_bDocAvail = false; + InternalStatus m_internalStatus = InternalStatus::kHeader; std::unique_ptr<CPDF_CrossRefAvail> m_pCrossRefAvail; - PDF_DATAAVAIL_STATUS m_docStatus = PDF_DATAAVAIL_HEADER; const FX_FILESIZE m_dwFileLen; UnownedPtr<CPDF_Document> m_pDocument; std::vector<uint32_t> m_PageObjList; + std::set<uint32_t> m_SeenPageObjList; uint32_t m_PagesObjNum = 0; bool m_bLinearedDataOK = false; bool m_bMainXRefLoadTried = false; @@ -187,15 +186,16 @@ std::vector<RetainPtr<CPDF_Object>> m_PagesArray; bool m_bTotalLoadPageTree = false; bool m_bCurPageDictLoadOK = false; + bool m_bHeaderAvail = false; PageNode m_PageNode; std::set<uint32_t> m_pageMapCheckState; std::set<uint32_t> m_pagesLoadState; std::unique_ptr<CPDF_HintTables> m_pHintTables; - const bool m_bSupportHintTable; std::map<uint32_t, std::unique_ptr<CPDF_PageObjectAvail>> m_PagesObjAvail; - std::map<const CPDF_Object*, std::unique_ptr<CPDF_PageObjectAvail>> + std::map<RetainPtr<const CPDF_Object>, + std::unique_ptr<CPDF_PageObjectAvail>, + std::less<>> m_PagesResourcesAvail; - bool m_bHeaderAvail = false; }; #endif // CORE_FPDFAPI_PARSER_CPDF_DATA_AVAIL_H_
diff --git a/core/fpdfapi/parser/cpdf_dictionary.cpp b/core/fpdfapi/parser/cpdf_dictionary.cpp index 6c4c6e6..bf6f593 100644 --- a/core/fpdfapi/parser/cpdf_dictionary.cpp +++ b/core/fpdfapi/parser/cpdf_dictionary.cpp
@@ -1,4 +1,4 @@ -// Copyright 2016 PDFium Authors. All rights reserved. +// Copyright 2016 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -19,9 +19,8 @@ #include "core/fpdfapi/parser/cpdf_string.h" #include "core/fpdfapi/parser/fpdf_parser_utility.h" #include "core/fxcrt/fx_stream.h" -#include "third_party/base/logging.h" -#include "third_party/base/ptr_util.h" -#include "third_party/base/stl_util.h" +#include "third_party/base/check.h" +#include "third_party/base/containers/contains.h" CPDF_Dictionary::CPDF_Dictionary() : CPDF_Dictionary(WeakPtr<ByteStringPool>()) {} @@ -34,7 +33,7 @@ // and break cyclic references. m_ObjNum = kInvalidObjNum; for (auto& it : m_Map) { - if (it.second && it.second->GetObjNum() == kInvalidObjNum) + if (it.second->GetObjNum() == kInvalidObjNum) it.second.Leak(); } } @@ -43,23 +42,7 @@ return kDictionary; } -CPDF_Dictionary* CPDF_Dictionary::GetDict() { - return this; -} - -const CPDF_Dictionary* CPDF_Dictionary::GetDict() const { - return this; -} - -bool CPDF_Dictionary::IsDictionary() const { - return true; -} - -CPDF_Dictionary* CPDF_Dictionary::AsDictionary() { - return this; -} - -const CPDF_Dictionary* CPDF_Dictionary::AsDictionary() const { +CPDF_Dictionary* CPDF_Dictionary::AsMutableDictionary() { return this; } @@ -74,126 +57,203 @@ auto pCopy = pdfium::MakeRetain<CPDF_Dictionary>(m_pPool); CPDF_DictionaryLocker locker(this); for (const auto& it : locker) { - if (!pdfium::ContainsKey(*pVisited, it.second.Get())) { + if (!pdfium::Contains(*pVisited, it.second.Get())) { std::set<const CPDF_Object*> visited(*pVisited); - if (auto obj = it.second->CloneNonCyclic(bDirect, &visited)) + auto obj = it.second->CloneNonCyclic(bDirect, &visited); + if (obj) pCopy->m_Map.insert(std::make_pair(it.first, std::move(obj))); } } return pCopy; } -const CPDF_Object* CPDF_Dictionary::GetObjectFor(const ByteString& key) const { +const CPDF_Object* CPDF_Dictionary::GetObjectForInternal( + const ByteString& key) const { auto it = m_Map.find(key); return it != m_Map.end() ? it->second.Get() : nullptr; } -CPDF_Object* CPDF_Dictionary::GetObjectFor(const ByteString& key) { - return const_cast<CPDF_Object*>( - static_cast<const CPDF_Dictionary*>(this)->GetObjectFor(key)); -} - -const CPDF_Object* CPDF_Dictionary::GetDirectObjectFor( +RetainPtr<const CPDF_Object> CPDF_Dictionary::GetObjectFor( const ByteString& key) const { - const CPDF_Object* p = GetObjectFor(key); - return p ? p->GetDirect() : nullptr; + return pdfium::WrapRetain(GetObjectForInternal(key)); } -CPDF_Object* CPDF_Dictionary::GetDirectObjectFor(const ByteString& key) { - return const_cast<CPDF_Object*>( - static_cast<const CPDF_Dictionary*>(this)->GetDirectObjectFor(key)); +RetainPtr<CPDF_Object> CPDF_Dictionary::GetMutableObjectFor( + const ByteString& key) { + return pdfium::WrapRetain( + const_cast<CPDF_Object*>(GetObjectForInternal(key))); } -ByteString CPDF_Dictionary::GetStringFor(const ByteString& key) const { - const CPDF_Object* p = GetObjectFor(key); +const CPDF_Object* CPDF_Dictionary::GetDirectObjectForInternal( + const ByteString& key) const { + const CPDF_Object* p = GetObjectForInternal(key); + return p ? p->GetDirectInternal() : nullptr; +} + +RetainPtr<const CPDF_Object> CPDF_Dictionary::GetDirectObjectFor( + const ByteString& key) const { + return pdfium::WrapRetain(GetDirectObjectForInternal(key)); +} + +RetainPtr<CPDF_Object> CPDF_Dictionary::GetMutableDirectObjectFor( + const ByteString& key) { + return pdfium::WrapRetain( + const_cast<CPDF_Object*>(GetDirectObjectForInternal(key))); +} + +ByteString CPDF_Dictionary::GetByteStringFor(const ByteString& key) const { + const CPDF_Object* p = GetObjectForInternal(key); return p ? p->GetString() : ByteString(); } -WideString CPDF_Dictionary::GetUnicodeTextFor(const ByteString& key) const { - const CPDF_Object* p = GetObjectFor(key); - if (const CPDF_Reference* pRef = ToReference(p)) - p = pRef->GetDirect(); - return p ? p->GetUnicodeText() : WideString(); -} - -ByteString CPDF_Dictionary::GetStringFor(const ByteString& key, - const ByteString& def) const { - const CPDF_Object* p = GetObjectFor(key); +ByteString CPDF_Dictionary::GetByteStringFor(const ByteString& key, + const ByteString& def) const { + const CPDF_Object* p = GetObjectForInternal(key); return p ? p->GetString() : ByteString(def); } -int CPDF_Dictionary::GetIntegerFor(const ByteString& key) const { - const CPDF_Object* p = GetObjectFor(key); - return p ? p->GetInteger() : 0; +WideString CPDF_Dictionary::GetUnicodeTextFor(const ByteString& key) const { + const CPDF_Object* p = GetObjectForInternal(key); + if (const CPDF_Reference* pRef = ToReference(p)) + p = pRef->GetDirectInternal(); + return p ? p->GetUnicodeText() : WideString(); } -int CPDF_Dictionary::GetIntegerFor(const ByteString& key, int def) const { - const CPDF_Object* p = GetObjectFor(key); - return p ? p->GetInteger() : def; -} - -float CPDF_Dictionary::GetNumberFor(const ByteString& key) const { - const CPDF_Object* p = GetObjectFor(key); - return p ? p->GetNumber() : 0; +ByteString CPDF_Dictionary::GetNameFor(const ByteString& key) const { + const CPDF_Name* p = ToName(GetObjectForInternal(key)); + return p ? p->GetString() : ByteString(); } bool CPDF_Dictionary::GetBooleanFor(const ByteString& key, bool bDefault) const { - const CPDF_Object* p = GetObjectFor(key); + const CPDF_Object* p = GetObjectForInternal(key); return ToBoolean(p) ? p->GetInteger() != 0 : bDefault; } -const CPDF_Dictionary* CPDF_Dictionary::GetDictFor( +int CPDF_Dictionary::GetIntegerFor(const ByteString& key) const { + const CPDF_Object* p = GetObjectForInternal(key); + return p ? p->GetInteger() : 0; +} + +int CPDF_Dictionary::GetIntegerFor(const ByteString& key, int def) const { + const CPDF_Object* p = GetObjectForInternal(key); + return p ? p->GetInteger() : def; +} + +int CPDF_Dictionary::GetDirectIntegerFor(const ByteString& key) const { + const CPDF_Number* p = ToNumber(GetObjectForInternal(key)); + return p ? p->GetInteger() : 0; +} + +float CPDF_Dictionary::GetFloatFor(const ByteString& key) const { + const CPDF_Object* p = GetObjectForInternal(key); + return p ? p->GetNumber() : 0; +} + +const CPDF_Dictionary* CPDF_Dictionary::GetDictInternal() const { + return this; +} + +const CPDF_Dictionary* CPDF_Dictionary::GetDictForInternal( const ByteString& key) const { - const CPDF_Object* p = GetDirectObjectFor(key); - if (!p) - return nullptr; - if (const CPDF_Dictionary* pDict = p->AsDictionary()) - return pDict; - if (const CPDF_Stream* pStream = p->AsStream()) - return pStream->GetDict(); - return nullptr; + const CPDF_Object* p = GetDirectObjectForInternal(key); + return p ? p->GetDictInternal() : nullptr; } -CPDF_Dictionary* CPDF_Dictionary::GetDictFor(const ByteString& key) { - return const_cast<CPDF_Dictionary*>( - static_cast<const CPDF_Dictionary*>(this)->GetDictFor(key)); +RetainPtr<const CPDF_Dictionary> CPDF_Dictionary::GetDictFor( + const ByteString& key) const { + return pdfium::WrapRetain(GetDictForInternal(key)); } -const CPDF_Array* CPDF_Dictionary::GetArrayFor(const ByteString& key) const { - return ToArray(GetDirectObjectFor(key)); +RetainPtr<CPDF_Dictionary> CPDF_Dictionary::GetMutableDictFor( + const ByteString& key) { + return pdfium::WrapRetain( + const_cast<CPDF_Dictionary*>(GetDictForInternal(key))); } -CPDF_Array* CPDF_Dictionary::GetArrayFor(const ByteString& key) { - return ToArray(GetDirectObjectFor(key)); +RetainPtr<CPDF_Dictionary> CPDF_Dictionary::GetOrCreateDictFor( + const ByteString& key) { + RetainPtr<CPDF_Dictionary> result = GetMutableDictFor(key); + if (result) + return result; + return SetNewFor<CPDF_Dictionary>(key); } -const CPDF_Stream* CPDF_Dictionary::GetStreamFor(const ByteString& key) const { - return ToStream(GetDirectObjectFor(key)); +const CPDF_Array* CPDF_Dictionary::GetArrayForInternal( + const ByteString& key) const { + return ToArray(GetDirectObjectForInternal(key)); } -CPDF_Stream* CPDF_Dictionary::GetStreamFor(const ByteString& key) { - return ToStream(GetDirectObjectFor(key)); +RetainPtr<const CPDF_Array> CPDF_Dictionary::GetArrayFor( + const ByteString& key) const { + return pdfium::WrapRetain(GetArrayForInternal(key)); +} + +RetainPtr<CPDF_Array> CPDF_Dictionary::GetMutableArrayFor( + const ByteString& key) { + return pdfium::WrapRetain(const_cast<CPDF_Array*>(GetArrayForInternal(key))); +} + +RetainPtr<CPDF_Array> CPDF_Dictionary::GetOrCreateArrayFor( + const ByteString& key) { + RetainPtr<CPDF_Array> result = GetMutableArrayFor(key); + if (result) + return result; + return SetNewFor<CPDF_Array>(key); +} + +const CPDF_Stream* CPDF_Dictionary::GetStreamForInternal( + const ByteString& key) const { + return ToStream(GetDirectObjectForInternal(key)); +} + +RetainPtr<const CPDF_Stream> CPDF_Dictionary::GetStreamFor( + const ByteString& key) const { + return pdfium::WrapRetain(GetStreamForInternal(key)); +} + +RetainPtr<CPDF_Stream> CPDF_Dictionary::GetMutableStreamFor( + const ByteString& key) { + return pdfium::WrapRetain( + const_cast<CPDF_Stream*>(GetStreamForInternal(key))); +} + +const CPDF_Number* CPDF_Dictionary::GetNumberForInternal( + const ByteString& key) const { + return ToNumber(GetObjectForInternal(key)); +} + +RetainPtr<const CPDF_Number> CPDF_Dictionary::GetNumberFor( + const ByteString& key) const { + return pdfium::WrapRetain(GetNumberForInternal(key)); +} + +const CPDF_String* CPDF_Dictionary::GetStringForInternal( + const ByteString& key) const { + return ToString(GetObjectForInternal(key)); +} + +RetainPtr<const CPDF_String> CPDF_Dictionary::GetStringFor( + const ByteString& key) const { + return pdfium::WrapRetain(GetStringForInternal(key)); } CFX_FloatRect CPDF_Dictionary::GetRectFor(const ByteString& key) const { - CFX_FloatRect rect; - const CPDF_Array* pArray = GetArrayFor(key); + const CPDF_Array* pArray = GetArrayForInternal(key); if (pArray) - rect = pArray->GetRect(); - return rect; + return pArray->GetRect(); + return CFX_FloatRect(); } CFX_Matrix CPDF_Dictionary::GetMatrixFor(const ByteString& key) const { - CFX_Matrix matrix; - const CPDF_Array* pArray = GetArrayFor(key); + const CPDF_Array* pArray = GetArrayForInternal(key); if (pArray) - matrix = pArray->GetMatrix(); - return matrix; + return pArray->GetMatrix(); + return CFX_Matrix(); } bool CPDF_Dictionary::KeyExist(const ByteString& key) const { - return pdfium::ContainsKey(m_Map, key); + return pdfium::Contains(m_Map, key); } std::vector<ByteString> CPDF_Dictionary::GetKeys() const { @@ -204,14 +264,19 @@ return result; } -CPDF_Object* CPDF_Dictionary::SetFor(const ByteString& key, - RetainPtr<CPDF_Object> pObj) { +void CPDF_Dictionary::SetFor(const ByteString& key, + RetainPtr<CPDF_Object> pObj) { + (void)SetForInternal(key, std::move(pObj)); +} + +CPDF_Object* CPDF_Dictionary::SetForInternal(const ByteString& key, + RetainPtr<CPDF_Object> pObj) { CHECK(!IsLocked()); if (!pObj) { m_Map.erase(key); return nullptr; } - ASSERT(pObj->IsInline()); + DCHECK(pObj->IsInline()); CPDF_Object* pRet = pObj.Get(); m_Map[MaybeIntern(key)] = std::move(pObj); return pRet; @@ -225,11 +290,11 @@ if (it == m_Map.end() || it->second->IsReference()) return; - CPDF_Object* pObj = pHolder->AddIndirectObject(std::move(it->second)); - it->second = pObj->MakeReference(pHolder); + pHolder->AddIndirectObject(it->second); + it->second = it->second->MakeReference(pHolder); } -RetainPtr<CPDF_Object> CPDF_Dictionary::RemoveFor(const ByteString& key) { +RetainPtr<CPDF_Object> CPDF_Dictionary::RemoveFor(ByteStringView key) { CHECK(!IsLocked()); RetainPtr<CPDF_Object> result; auto it = m_Map.find(key); @@ -257,22 +322,22 @@ void CPDF_Dictionary::SetRectFor(const ByteString& key, const CFX_FloatRect& rect) { - CPDF_Array* pArray = SetNewFor<CPDF_Array>(key); - pArray->AddNew<CPDF_Number>(rect.left); - pArray->AddNew<CPDF_Number>(rect.bottom); - pArray->AddNew<CPDF_Number>(rect.right); - pArray->AddNew<CPDF_Number>(rect.top); + auto pArray = SetNewFor<CPDF_Array>(key); + pArray->AppendNew<CPDF_Number>(rect.left); + pArray->AppendNew<CPDF_Number>(rect.bottom); + pArray->AppendNew<CPDF_Number>(rect.right); + pArray->AppendNew<CPDF_Number>(rect.top); } void CPDF_Dictionary::SetMatrixFor(const ByteString& key, const CFX_Matrix& matrix) { - CPDF_Array* pArray = SetNewFor<CPDF_Array>(key); - pArray->AddNew<CPDF_Number>(matrix.a); - pArray->AddNew<CPDF_Number>(matrix.b); - pArray->AddNew<CPDF_Number>(matrix.c); - pArray->AddNew<CPDF_Number>(matrix.d); - pArray->AddNew<CPDF_Number>(matrix.e); - pArray->AddNew<CPDF_Number>(matrix.f); + auto pArray = SetNewFor<CPDF_Array>(key); + pArray->AppendNew<CPDF_Number>(matrix.a); + pArray->AppendNew<CPDF_Number>(matrix.b); + pArray->AppendNew<CPDF_Number>(matrix.c); + pArray->AppendNew<CPDF_Number>(matrix.d); + pArray->AppendNew<CPDF_Number>(matrix.e); + pArray->AppendNew<CPDF_Number>(matrix.f); } ByteString CPDF_Dictionary::MaybeIntern(const ByteString& str) { @@ -289,7 +354,7 @@ CPDF_DictionaryLocker locker(this); for (const auto& it : locker) { const ByteString& key = it.first; - CPDF_Object* pValue = it.second.Get(); + const RetainPtr<CPDF_Object>& pValue = it.second; if (!archive->WriteString("/") || !archive->WriteString(PDF_NameEncode(key).AsStringView())) { return false; @@ -308,6 +373,18 @@ m_pDictionary->m_LockCount++; } +CPDF_DictionaryLocker::CPDF_DictionaryLocker( + RetainPtr<CPDF_Dictionary> pDictionary) + : m_pDictionary(std::move(pDictionary)) { + m_pDictionary->m_LockCount++; +} + +CPDF_DictionaryLocker::CPDF_DictionaryLocker( + RetainPtr<const CPDF_Dictionary> pDictionary) + : m_pDictionary(std::move(pDictionary)) { + m_pDictionary->m_LockCount++; +} + CPDF_DictionaryLocker::~CPDF_DictionaryLocker() { m_pDictionary->m_LockCount--; }
diff --git a/core/fpdfapi/parser/cpdf_dictionary.h b/core/fpdfapi/parser/cpdf_dictionary.h index ac1b226..34be276 100644 --- a/core/fpdfapi/parser/cpdf_dictionary.h +++ b/core/fpdfapi/parser/cpdf_dictionary.h
@@ -1,4 +1,4 @@ -// Copyright 2016 PDFium Authors. All rights reserved. +// Copyright 2016 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -7,8 +7,8 @@ #ifndef CORE_FPDFAPI_PARSER_CPDF_DICTIONARY_H_ #define CORE_FPDFAPI_PARSER_CPDF_DICTIONARY_H_ +#include <functional> #include <map> -#include <memory> #include <set> #include <utility> #include <vector> @@ -19,92 +19,100 @@ #include "core/fxcrt/retain_ptr.h" #include "core/fxcrt/string_pool_template.h" #include "core/fxcrt/weak_ptr.h" -#include "third_party/base/logging.h" -#include "third_party/base/ptr_util.h" +#include "third_party/base/check.h" class CPDF_IndirectObjectHolder; +// Dictionaries never contain nullptr for valid keys, but some of the methods +// will return nullptr to indicate non-existent keys. class CPDF_Dictionary final : public CPDF_Object { public: - using const_iterator = - std::map<ByteString, RetainPtr<CPDF_Object>>::const_iterator; + using DictMap = std::map<ByteString, RetainPtr<CPDF_Object>, std::less<>>; + using const_iterator = DictMap::const_iterator; - template <typename T, typename... Args> - friend RetainPtr<T> pdfium::MakeRetain(Args&&... args); + CONSTRUCT_VIA_MAKE_RETAIN; // CPDF_Object: Type GetType() const override; RetainPtr<CPDF_Object> Clone() const override; - CPDF_Dictionary* GetDict() override; - const CPDF_Dictionary* GetDict() const override; - bool IsDictionary() const override; - CPDF_Dictionary* AsDictionary() override; - const CPDF_Dictionary* AsDictionary() const override; + CPDF_Dictionary* AsMutableDictionary() override; bool WriteTo(IFX_ArchiveStream* archive, const CPDF_Encryptor* encryptor) const override; bool IsLocked() const { return !!m_LockCount; } size_t size() const { return m_Map.size(); } - const CPDF_Object* GetObjectFor(const ByteString& key) const; - CPDF_Object* GetObjectFor(const ByteString& key); - const CPDF_Object* GetDirectObjectFor(const ByteString& key) const; - CPDF_Object* GetDirectObjectFor(const ByteString& key); - ByteString GetStringFor(const ByteString& key) const; - ByteString GetStringFor(const ByteString& key, - const ByteString& default_str) const; + RetainPtr<const CPDF_Object> GetObjectFor(const ByteString& key) const; + RetainPtr<CPDF_Object> GetMutableObjectFor(const ByteString& key); + + RetainPtr<const CPDF_Object> GetDirectObjectFor(const ByteString& key) const; + RetainPtr<CPDF_Object> GetMutableDirectObjectFor(const ByteString& key); + + // These will return the string representation of the object specified by + // |key|, for any object type that has a string representation. + ByteString GetByteStringFor(const ByteString& key) const; + ByteString GetByteStringFor(const ByteString& key, + const ByteString& default_str) const; WideString GetUnicodeTextFor(const ByteString& key) const; + + // This will only return the string representation of a name object specified + // by |key|. Useful when the PDF spec requires the value to be an object of + // type name. i.e. /Foo and not (Foo). + ByteString GetNameFor(const ByteString& key) const; + + bool GetBooleanFor(const ByteString& key, bool bDefault) const; int GetIntegerFor(const ByteString& key) const; int GetIntegerFor(const ByteString& key, int default_int) const; - bool GetBooleanFor(const ByteString& key, bool bDefault) const; - float GetNumberFor(const ByteString& key) const; - const CPDF_Dictionary* GetDictFor(const ByteString& key) const; - CPDF_Dictionary* GetDictFor(const ByteString& key); - const CPDF_Stream* GetStreamFor(const ByteString& key) const; - CPDF_Stream* GetStreamFor(const ByteString& key); - const CPDF_Array* GetArrayFor(const ByteString& key) const; - CPDF_Array* GetArrayFor(const ByteString& key); + int GetDirectIntegerFor(const ByteString& key) const; + float GetFloatFor(const ByteString& key) const; + RetainPtr<const CPDF_Dictionary> GetDictFor(const ByteString& key) const; + RetainPtr<CPDF_Dictionary> GetMutableDictFor(const ByteString& key); + RetainPtr<CPDF_Dictionary> GetOrCreateDictFor(const ByteString& key); + RetainPtr<const CPDF_Array> GetArrayFor(const ByteString& key) const; + RetainPtr<CPDF_Array> GetMutableArrayFor(const ByteString& key); + RetainPtr<CPDF_Array> GetOrCreateArrayFor(const ByteString& key); + RetainPtr<const CPDF_Stream> GetStreamFor(const ByteString& key) const; + RetainPtr<CPDF_Stream> GetMutableStreamFor(const ByteString& key); + RetainPtr<const CPDF_Number> GetNumberFor(const ByteString& key) const; + RetainPtr<const CPDF_String> GetStringFor(const ByteString& key) const; CFX_FloatRect GetRectFor(const ByteString& key) const; CFX_Matrix GetMatrixFor(const ByteString& key) const; - float GetFloatFor(const ByteString& key) const { return GetNumberFor(key); } bool KeyExist(const ByteString& key) const; std::vector<ByteString> GetKeys() const; // Creates a new object owned by the dictionary and returns an unowned - // pointer to it. Prefer using these templates over calls to SetFor(), - // since by creating a new object with no previous references, they ensure - // cycles can not be introduced. + // pointer to it. Invalidates iterators for the element with the key |key|. + // Prefer using these templates over calls to SetFor(), since by creating + // a new object with no previous references, they ensure cycles can not be + // introduced. template <typename T, typename... Args> - typename std::enable_if<!CanInternStrings<T>::value, T*>::type SetNewFor( - const ByteString& key, - Args&&... args) { - CHECK(!IsLocked()); - return static_cast<T*>( - SetFor(key, pdfium::MakeRetain<T>(std::forward<Args>(args)...))); + typename std::enable_if<!CanInternStrings<T>::value, RetainPtr<T>>::type + SetNewFor(const ByteString& key, Args&&... args) { + return pdfium::WrapRetain(static_cast<T*>(SetForInternal( + key, pdfium::MakeRetain<T>(std::forward<Args>(args)...)))); } template <typename T, typename... Args> - typename std::enable_if<CanInternStrings<T>::value, T*>::type SetNewFor( - const ByteString& key, - Args&&... args) { - CHECK(!IsLocked()); - return static_cast<T*>(SetFor( - key, pdfium::MakeRetain<T>(m_pPool, std::forward<Args>(args)...))); + typename std::enable_if<CanInternStrings<T>::value, RetainPtr<T>>::type + SetNewFor(const ByteString& key, Args&&... args) { + return pdfium::WrapRetain(static_cast<T*>(SetForInternal( + key, pdfium::MakeRetain<T>(m_pPool, std::forward<Args>(args)...)))); } + // If |pObj| is null, then |key| is erased from the map. Otherwise, takes + // ownership of |pObj| and stores in in the map. Invalidates iterators for + // the element with the key |key|. + void SetFor(const ByteString& key, RetainPtr<CPDF_Object> pObj); + // Convenience functions to convert native objects to array form. void SetRectFor(const ByteString& key, const CFX_FloatRect& rect); void SetMatrixFor(const ByteString& key, const CFX_Matrix& matrix); - // Set* functions invalidate iterators for the element with the key |key|. - // Takes ownership of |pObj|, returns an unowned pointer to it. - CPDF_Object* SetFor(const ByteString& key, RetainPtr<CPDF_Object> pObj); - void ConvertToIndirectObjectFor(const ByteString& key, CPDF_IndirectObjectHolder* pHolder); // Invalidates iterators for the element with the key |key|. - RetainPtr<CPDF_Object> RemoveFor(const ByteString& key); + RetainPtr<CPDF_Object> RemoveFor(ByteStringView key); // Invalidates iterators for the element with the key |oldkey|. void ReplaceKey(const ByteString& oldkey, const ByteString& newkey); @@ -118,21 +126,36 @@ explicit CPDF_Dictionary(const WeakPtr<ByteStringPool>& pPool); ~CPDF_Dictionary() override; + // No guarantees about result lifetime, use with caution. + const CPDF_Object* GetObjectForInternal(const ByteString& key) const; + const CPDF_Object* GetDirectObjectForInternal(const ByteString& key) const; + const CPDF_Array* GetArrayForInternal(const ByteString& key) const; + const CPDF_Dictionary* GetDictForInternal(const ByteString& key) const; + const CPDF_Number* GetNumberForInternal(const ByteString& key) const; + const CPDF_Stream* GetStreamForInternal(const ByteString& key) const; + const CPDF_String* GetStringForInternal(const ByteString& key) const; + CPDF_Object* SetForInternal(const ByteString& key, + RetainPtr<CPDF_Object> pObj); + ByteString MaybeIntern(const ByteString& str); + const CPDF_Dictionary* GetDictInternal() const override; RetainPtr<CPDF_Object> CloneNonCyclic( bool bDirect, std::set<const CPDF_Object*>* visited) const override; mutable uint32_t m_LockCount = 0; WeakPtr<ByteStringPool> m_pPool; - std::map<ByteString, RetainPtr<CPDF_Object>> m_Map; + DictMap m_Map; }; class CPDF_DictionaryLocker { public: + FX_STACK_ALLOCATED(); using const_iterator = CPDF_Dictionary::const_iterator; explicit CPDF_DictionaryLocker(const CPDF_Dictionary* pDictionary); + explicit CPDF_DictionaryLocker(RetainPtr<CPDF_Dictionary> pDictionary); + explicit CPDF_DictionaryLocker(RetainPtr<const CPDF_Dictionary> pDictionary); ~CPDF_DictionaryLocker(); const_iterator begin() const { @@ -149,7 +172,7 @@ }; inline CPDF_Dictionary* ToDictionary(CPDF_Object* obj) { - return obj ? obj->AsDictionary() : nullptr; + return obj ? obj->AsMutableDictionary() : nullptr; } inline const CPDF_Dictionary* ToDictionary(const CPDF_Object* obj) { @@ -160,4 +183,9 @@ return RetainPtr<CPDF_Dictionary>(ToDictionary(obj.Get())); } +inline RetainPtr<const CPDF_Dictionary> ToDictionary( + RetainPtr<const CPDF_Object> obj) { + return RetainPtr<const CPDF_Dictionary>(ToDictionary(obj.Get())); +} + #endif // CORE_FPDFAPI_PARSER_CPDF_DICTIONARY_H_
diff --git a/core/fpdfapi/parser/cpdf_dictionary_unittest.cpp b/core/fpdfapi/parser/cpdf_dictionary_unittest.cpp new file mode 100644 index 0000000..84acc3a --- /dev/null +++ b/core/fpdfapi/parser/cpdf_dictionary_unittest.cpp
@@ -0,0 +1,44 @@ +// Copyright 2022 The PDFium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "core/fpdfapi/parser/cpdf_dictionary.h" + +#include <utility> + +#include "core/fpdfapi/parser/cpdf_array.h" +#include "core/fpdfapi/parser/cpdf_number.h" +#include "core/fpdfapi/parser/cpdf_stream.h" +#include "testing/gtest/include/gtest/gtest.h" + +TEST(DictionaryTest, Iterators) { + auto dict = pdfium::MakeRetain<CPDF_Dictionary>(); + dict->SetNewFor<CPDF_Dictionary>("the-dictionary"); + dict->SetNewFor<CPDF_Array>("the-array"); + dict->SetNewFor<CPDF_Stream>("the-stream"); + dict->SetNewFor<CPDF_Number>("the-number", 42); + + CPDF_DictionaryLocker locked_dict(dict); + auto it = locked_dict.begin(); + EXPECT_NE(it, locked_dict.end()); + EXPECT_EQ(it->first, ByteString("the-array")); + EXPECT_TRUE(it->second->IsArray()); + + ++it; + EXPECT_NE(it, locked_dict.end()); + EXPECT_EQ(it->first, ByteString("the-dictionary")); + EXPECT_TRUE(it->second->IsDictionary()); + + ++it; + EXPECT_NE(it, locked_dict.end()); + EXPECT_EQ(it->first, ByteString("the-number")); + EXPECT_TRUE(it->second->IsNumber()); + + ++it; + EXPECT_NE(it, locked_dict.end()); + EXPECT_EQ(it->first, ByteString("the-stream")); + EXPECT_TRUE(it->second->IsStream()); + + ++it; + EXPECT_EQ(it, locked_dict.end()); +}
diff --git a/core/fpdfapi/parser/cpdf_document.cpp b/core/fpdfapi/parser/cpdf_document.cpp index d26d5c4..ee9dfcd 100644 --- a/core/fpdfapi/parser/cpdf_document.cpp +++ b/core/fpdfapi/parser/cpdf_document.cpp
@@ -1,4 +1,4 @@ -// Copyright 2014 PDFium Authors. All rights reserved. +// Copyright 2014 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -6,11 +6,8 @@ #include "core/fpdfapi/parser/cpdf_document.h" -#include <set> #include <utility> -#include <vector> -#include "build/build_config.h" #include "core/fpdfapi/parser/cpdf_array.h" #include "core/fpdfapi/parser/cpdf_dictionary.h" #include "core/fpdfapi/parser/cpdf_linearized_header.h" @@ -21,43 +18,109 @@ #include "core/fpdfapi/parser/cpdf_reference.h" #include "core/fpdfapi/parser/cpdf_stream.h" #include "core/fpdfapi/parser/cpdf_stream_acc.h" -#include "core/fpdfapi/parser/cpdf_string.h" +#include "core/fpdfapi/parser/fpdf_parser_utility.h" #include "core/fxcodec/jbig2/JBig2_DocumentContext.h" #include "core/fxcrt/fx_codepage.h" -#include "third_party/base/ptr_util.h" -#include "third_party/base/stl_util.h" +#include "core/fxcrt/scoped_set_insertion.h" +#include "core/fxcrt/stl_util.h" +#include "third_party/abseil-cpp/absl/types/optional.h" +#include "third_party/base/check.h" +#include "third_party/base/containers/contains.h" namespace { const int kMaxPageLevel = 1024; -int CountPages(CPDF_Dictionary* pPages, - std::set<CPDF_Dictionary*>* visited_pages) { +// Returns a value in the range [0, `CPDF_Document::kPageMaxNum`), or nullopt on +// error. +absl::optional<int> CountPages( + RetainPtr<CPDF_Dictionary> pPages, + std::set<RetainPtr<CPDF_Dictionary>>* visited_pages) { int count = pPages->GetIntegerFor("Count"); if (count > 0 && count < CPDF_Document::kPageMaxNum) return count; - CPDF_Array* pKidList = pPages->GetArrayFor("Kids"); + RetainPtr<CPDF_Array> pKidList = pPages->GetMutableArrayFor("Kids"); if (!pKidList) return 0; count = 0; for (size_t i = 0; i < pKidList->size(); i++) { - CPDF_Dictionary* pKid = pKidList->GetDictAt(i); - if (!pKid || pdfium::ContainsKey(*visited_pages, pKid)) + RetainPtr<CPDF_Dictionary> pKid = pKidList->GetMutableDictAt(i); + if (!pKid || pdfium::Contains(*visited_pages, pKid)) continue; if (pKid->KeyExist("Kids")) { // Use |visited_pages| to help detect circular references of pages. - pdfium::ScopedSetInsertion<CPDF_Dictionary*> local_add(visited_pages, - pKid); - count += CountPages(pKid, visited_pages); + ScopedSetInsertion<RetainPtr<CPDF_Dictionary>> local_add(visited_pages, + pKid); + absl::optional<int> local_count = + CountPages(std::move(pKid), visited_pages); + if (!local_count.has_value()) { + return absl::nullopt; // Propagate error. + } + count += local_count.value(); } else { // This page is a leaf node. count++; } + if (count >= CPDF_Document::kPageMaxNum) { + return absl::nullopt; // Error: too many pages. + } } pPages->SetNewFor<CPDF_Number>("Count", count); return count; } +int FindPageIndex(const CPDF_Dictionary* pNode, + uint32_t* skip_count, + uint32_t objnum, + int* index, + int level) { + if (!pNode->KeyExist("Kids")) { + if (objnum == pNode->GetObjNum()) + return *index; + + if (*skip_count != 0) + (*skip_count)--; + + (*index)++; + return -1; + } + + RetainPtr<const CPDF_Array> pKidList = pNode->GetArrayFor("Kids"); + if (!pKidList) + return -1; + + if (level >= kMaxPageLevel) + return -1; + + size_t count = pNode->GetIntegerFor("Count"); + if (count <= *skip_count) { + (*skip_count) -= count; + (*index) += count; + return -1; + } + + if (count && count == pKidList->size()) { + for (size_t i = 0; i < count; i++) { + RetainPtr<const CPDF_Reference> pKid = + ToReference(pKidList->GetObjectAt(i)); + if (pKid && pKid->GetRefObjNum() == objnum) + return static_cast<int>(*index + i); + } + } + + for (size_t i = 0; i < pKidList->size(); i++) { + RetainPtr<const CPDF_Dictionary> pKid = pKidList->GetDictAt(i); + if (!pKid || pKid == pNode) + continue; + + int found_index = + FindPageIndex(pKid.Get(), skip_count, objnum, index, level + 1); + if (found_index >= 0) + return found_index; + } + return -1; +} + } // namespace CPDF_Document::CPDF_Document(std::unique_ptr<RenderDataIface> pRenderData, @@ -69,7 +132,19 @@ m_pDocPage->SetDocument(this); } -CPDF_Document::~CPDF_Document() = default; +CPDF_Document::~CPDF_Document() { + // Be absolutely certain that |m_pExtension| is null before destroying + // the extension, to avoid re-entering it while being destroyed. clang + // seems to already do this for us, but the C++ standards seem to + // indicate the opposite. + m_pExtension.reset(); +} + +// static +bool CPDF_Document::IsValidPageObject(const CPDF_Object* obj) { + // See ISO 32000-1:2008 spec, table 30. + return ValidateDictType(ToDictionary(obj), "Page"); +} RetainPtr<CPDF_Object> CPDF_Document::ParseIndirectObject(uint32_t objnum) { return m_pParser ? m_pParser->ParseIndirectObject(objnum) : nullptr; @@ -78,30 +153,33 @@ bool CPDF_Document::TryInit() { SetLastObjNum(m_pParser->GetLastObjNum()); - CPDF_Object* pRootObj = GetOrParseIndirectObject(m_pParser->GetRootObjNum()); + RetainPtr<CPDF_Object> pRootObj = + GetOrParseIndirectObject(m_pParser->GetRootObjNum()); if (pRootObj) - m_pRootDict.Reset(pRootObj->GetDict()); + m_pRootDict = pRootObj->GetMutableDict(); LoadPages(); return GetRoot() && GetPageCount() > 0; } CPDF_Parser::Error CPDF_Document::LoadDoc( - const RetainPtr<IFX_SeekableReadStream>& pFileAccess, - const char* password) { + RetainPtr<IFX_SeekableReadStream> pFileAccess, + const ByteString& password) { if (!m_pParser) - SetParser(pdfium::MakeUnique<CPDF_Parser>(this)); + SetParser(std::make_unique<CPDF_Parser>(this)); - return HandleLoadResult(m_pParser->StartParse(pFileAccess, password)); + return HandleLoadResult( + m_pParser->StartParse(std::move(pFileAccess), password)); } CPDF_Parser::Error CPDF_Document::LoadLinearizedDoc( - const RetainPtr<CPDF_ReadValidator>& validator, - const char* password) { + RetainPtr<CPDF_ReadValidator> validator, + const ByteString& password) { if (!m_pParser) - SetParser(pdfium::MakeUnique<CPDF_Parser>(this)); + SetParser(std::make_unique<CPDF_Parser>(this)); - return HandleLoadResult(m_pParser->StartLinearizedParse(validator, password)); + return HandleLoadResult( + m_pParser->StartLinearizedParse(std::move(validator), password)); } void CPDF_Document::LoadPages() { @@ -112,20 +190,27 @@ return; } - m_PageList.resize(linearized_header->GetPageCount()); - ASSERT(linearized_header->GetFirstPageNo() < m_PageList.size()); - m_PageList[linearized_header->GetFirstPageNo()] = - linearized_header->GetFirstPageObjNum(); + uint32_t objnum = linearized_header->GetFirstPageObjNum(); + if (!IsValidPageObject(GetOrParseIndirectObject(objnum).Get())) { + m_PageList.resize(RetrievePageCount()); + return; + } + + uint32_t first_page_num = linearized_header->GetFirstPageNo(); + uint32_t page_count = linearized_header->GetPageCount(); + DCHECK(first_page_num < page_count); + m_PageList.resize(page_count); + m_PageList[first_page_num] = objnum; } -CPDF_Dictionary* CPDF_Document::TraversePDFPages(int iPage, - int* nPagesToGo, - size_t level) { +RetainPtr<CPDF_Dictionary> CPDF_Document::TraversePDFPages(int iPage, + int* nPagesToGo, + size_t level) { if (*nPagesToGo < 0 || m_bReachedMaxPageLevel) return nullptr; - CPDF_Dictionary* pPages = m_pTreeTraversal[level].first; - CPDF_Array* pKidList = pPages->GetArrayFor("Kids"); + RetainPtr<CPDF_Dictionary> pPages = m_pTreeTraversal[level].first; + RetainPtr<CPDF_Array> pKidList = pPages->GetMutableArrayFor("Kids"); if (!pKidList) { m_pTreeTraversal.pop_back(); if (*nPagesToGo != 1) @@ -138,12 +223,12 @@ m_bReachedMaxPageLevel = true; return nullptr; } - CPDF_Dictionary* page = nullptr; + RetainPtr<CPDF_Dictionary> page; for (size_t i = m_pTreeTraversal[level].second; i < pKidList->size(); i++) { if (*nPagesToGo == 0) break; pKidList->ConvertToIndirectObjectAt(i, this); - CPDF_Dictionary* pKid = pKidList->GetDictAt(i); + RetainPtr<CPDF_Dictionary> pKid = pKidList->GetMutableDictAt(i); if (!pKid) { (*nPagesToGo)--; m_pTreeTraversal[level].second++; @@ -158,22 +243,23 @@ (*nPagesToGo)--; m_pTreeTraversal[level].second++; if (*nPagesToGo == 0) { - page = pKid; + page = std::move(pKid); break; } } else { // If the vector has size level+1, the child is not in yet if (m_pTreeTraversal.size() == level + 1) - m_pTreeTraversal.push_back(std::make_pair(pKid, 0)); + m_pTreeTraversal.emplace_back(std::move(pKid), 0); // Now m_pTreeTraversal[level+1] should exist and be equal to pKid. - CPDF_Dictionary* pageKid = TraversePDFPages(iPage, nPagesToGo, level + 1); + RetainPtr<CPDF_Dictionary> pPageKid = + TraversePDFPages(iPage, nPagesToGo, level + 1); // Check if child was completely processed, i.e. it popped itself out if (m_pTreeTraversal.size() == level + 1) m_pTreeTraversal[level].second++; // If child did not finish, no pages to go, or max level reached, end if (m_pTreeTraversal.size() != level + 1 || *nPagesToGo == 0 || m_bReachedMaxPageLevel) { - page = pageKid; + page = std::move(pPageKid); break; } } @@ -190,7 +276,7 @@ } void CPDF_Document::SetParser(std::unique_ptr<CPDF_Parser> pParser) { - ASSERT(!m_pParser); + DCHECK(!m_pParser); m_pParser = std::move(pParser); } @@ -200,104 +286,75 @@ return error; } -const CPDF_Dictionary* CPDF_Document::GetPagesDict() const { +RetainPtr<const CPDF_Dictionary> CPDF_Document::GetPagesDict() const { const CPDF_Dictionary* pRoot = GetRoot(); return pRoot ? pRoot->GetDictFor("Pages") : nullptr; } -CPDF_Dictionary* CPDF_Document::GetPagesDict() { - return const_cast<CPDF_Dictionary*>( - static_cast<const CPDF_Document*>(this)->GetPagesDict()); +RetainPtr<CPDF_Dictionary> CPDF_Document::GetMutablePagesDict() { + return pdfium::WrapRetain( + const_cast<CPDF_Dictionary*>(this->GetPagesDict().Get())); } bool CPDF_Document::IsPageLoaded(int iPage) const { return !!m_PageList[iPage]; } -CPDF_Dictionary* CPDF_Document::GetPageDictionary(int iPage) { - if (!pdfium::IndexInBounds(m_PageList, iPage)) +RetainPtr<const CPDF_Dictionary> CPDF_Document::GetPageDictionary(int iPage) { + if (!fxcrt::IndexInBounds(m_PageList, iPage)) return nullptr; const uint32_t objnum = m_PageList[iPage]; if (objnum) { - CPDF_Dictionary* result = ToDictionary(GetOrParseIndirectObject(objnum)); + RetainPtr<CPDF_Dictionary> result = + ToDictionary(GetOrParseIndirectObject(objnum)); if (result) return result; } - CPDF_Dictionary* pPages = GetPagesDict(); + RetainPtr<CPDF_Dictionary> pPages = GetMutablePagesDict(); if (!pPages) return nullptr; if (m_pTreeTraversal.empty()) { ResetTraversal(); - m_pTreeTraversal.push_back(std::make_pair(pPages, 0)); + m_pTreeTraversal.emplace_back(std::move(pPages), 0); } int nPagesToGo = iPage - m_iNextPageToTraverse + 1; - CPDF_Dictionary* pPage = TraversePDFPages(iPage, &nPagesToGo, 0); + RetainPtr<CPDF_Dictionary> pPage = TraversePDFPages(iPage, &nPagesToGo, 0); m_iNextPageToTraverse = iPage + 1; return pPage; } +RetainPtr<CPDF_Dictionary> CPDF_Document::GetMutablePageDictionary(int iPage) { + return pdfium::WrapRetain( + const_cast<CPDF_Dictionary*>(GetPageDictionary(iPage).Get())); +} + void CPDF_Document::SetPageObjNum(int iPage, uint32_t objNum) { m_PageList[iPage] = objNum; } -int CPDF_Document::FindPageIndex(const CPDF_Dictionary* pNode, - uint32_t* skip_count, - uint32_t objnum, - int* index, - int level) const { - if (!pNode->KeyExist("Kids")) { - if (objnum == pNode->GetObjNum()) - return *index; +JBig2_DocumentContext* CPDF_Document::GetOrCreateCodecContext() { + if (!m_pCodecContext) + m_pCodecContext = std::make_unique<JBig2_DocumentContext>(); + return m_pCodecContext.get(); +} - if (*skip_count) - (*skip_count)--; +RetainPtr<CPDF_Stream> CPDF_Document::CreateModifiedAPStream() { + auto stream = NewIndirect<CPDF_Stream>(); + m_ModifiedAPStreamIDs.insert(stream->GetObjNum()); + return stream; +} - (*index)++; - return -1; - } - - const CPDF_Array* pKidList = pNode->GetArrayFor("Kids"); - if (!pKidList) - return -1; - - if (level >= kMaxPageLevel) - return -1; - - size_t count = pNode->GetIntegerFor("Count"); - if (count <= *skip_count) { - (*skip_count) -= count; - (*index) += count; - return -1; - } - - if (count && count == pKidList->size()) { - for (size_t i = 0; i < count; i++) { - const CPDF_Reference* pKid = ToReference(pKidList->GetObjectAt(i)); - if (pKid && pKid->GetRefObjNum() == objnum) - return static_cast<int>(*index + i); - } - } - - for (size_t i = 0; i < pKidList->size(); i++) { - const CPDF_Dictionary* pKid = pKidList->GetDictAt(i); - if (!pKid || pKid == pNode) - continue; - - int found_index = FindPageIndex(pKid, skip_count, objnum, index, level + 1); - if (found_index >= 0) - return found_index; - } - return -1; +bool CPDF_Document::IsModifiedAPStream(const CPDF_Stream* stream) const { + return stream && pdfium::Contains(m_ModifiedAPStreamIDs, stream->GetObjNum()); } int CPDF_Document::GetPageIndex(uint32_t objnum) { - uint32_t nPages = m_PageList.size(); uint32_t skip_count = 0; bool bSkipped = false; - for (uint32_t i = 0; i < nPages; i++) { + for (uint32_t i = 0; i < m_PageList.size(); ++i) { if (m_PageList[i] == objnum) return i; @@ -306,7 +363,7 @@ bSkipped = true; } } - const CPDF_Dictionary* pPages = GetPagesDict(); + RetainPtr<const CPDF_Dictionary> pPages = GetPagesDict(); if (!pPages) return -1; @@ -314,28 +371,29 @@ int found_index = FindPageIndex(pPages, &skip_count, objnum, &start_index, 0); // Corrupt page tree may yield out-of-range results. - if (!pdfium::IndexInBounds(m_PageList, found_index)) + if (!fxcrt::IndexInBounds(m_PageList, found_index)) return -1; - m_PageList[found_index] = objnum; + // Only update |m_PageList| when |objnum| points to a /Page object. + if (IsValidPageObject(GetOrParseIndirectObject(objnum).Get())) + m_PageList[found_index] = objnum; return found_index; } int CPDF_Document::GetPageCount() const { - return pdfium::CollectionSize<int>(m_PageList); + return fxcrt::CollectionSize<int>(m_PageList); } int CPDF_Document::RetrievePageCount() { - CPDF_Dictionary* pPages = GetPagesDict(); + RetainPtr<CPDF_Dictionary> pPages = GetMutablePagesDict(); if (!pPages) return 0; if (!pPages->KeyExist("Kids")) return 1; - std::set<CPDF_Dictionary*> visited_pages; - visited_pages.insert(pPages); - return CountPages(pPages, &visited_pages); + std::set<RetainPtr<CPDF_Dictionary>> visited_pages = {pPages}; + return CountPages(std::move(pPages), &visited_pages).value_or(0); } uint32_t CPDF_Document::GetUserPermissions() const { @@ -345,22 +403,38 @@ return m_pExtension ? m_pExtension->GetUserPermissions() : 0; } +RetainPtr<CPDF_StreamAcc> CPDF_Document::GetFontFileStreamAcc( + RetainPtr<const CPDF_Stream> pFontStream) { + return m_pDocPage->GetFontFileStreamAcc(std::move(pFontStream)); +} + +void CPDF_Document::MaybePurgeFontFileStreamAcc( + RetainPtr<CPDF_StreamAcc>&& pStreamAcc) { + if (m_pDocPage) + m_pDocPage->MaybePurgeFontFileStreamAcc(std::move(pStreamAcc)); +} + +void CPDF_Document::MaybePurgeImage(uint32_t objnum) { + if (m_pDocPage) + m_pDocPage->MaybePurgeImage(objnum); +} + void CPDF_Document::CreateNewDoc() { - ASSERT(!m_pRootDict); - ASSERT(!m_pInfoDict); - m_pRootDict.Reset(NewIndirect<CPDF_Dictionary>()); + DCHECK(!m_pRootDict); + DCHECK(!m_pInfoDict); + m_pRootDict = NewIndirect<CPDF_Dictionary>(); m_pRootDict->SetNewFor<CPDF_Name>("Type", "Catalog"); - CPDF_Dictionary* pPages = NewIndirect<CPDF_Dictionary>(); + auto pPages = NewIndirect<CPDF_Dictionary>(); pPages->SetNewFor<CPDF_Name>("Type", "Pages"); pPages->SetNewFor<CPDF_Number>("Count", 0); pPages->SetNewFor<CPDF_Array>("Kids"); m_pRootDict->SetNewFor<CPDF_Reference>("Pages", this, pPages->GetObjNum()); - m_pInfoDict.Reset(NewIndirect<CPDF_Dictionary>()); + m_pInfoDict = NewIndirect<CPDF_Dictionary>(); } -CPDF_Dictionary* CPDF_Document::CreateNewPage(int iPage) { - CPDF_Dictionary* pDict = NewIndirect<CPDF_Dictionary>(); +RetainPtr<CPDF_Dictionary> CPDF_Document::CreateNewPage(int iPage) { + auto pDict = NewIndirect<CPDF_Dictionary>(); pDict->SetNewFor<CPDF_Name>("Type", "Page"); uint32_t dwObjNum = pDict->GetObjNum(); if (!InsertNewPage(iPage, pDict)) { @@ -370,18 +444,19 @@ return pDict; } -bool CPDF_Document::InsertDeletePDFPage(CPDF_Dictionary* pPages, - int nPagesToGo, - CPDF_Dictionary* pPageDict, - bool bInsert, - std::set<CPDF_Dictionary*>* pVisited) { - CPDF_Array* pKidList = pPages->GetArrayFor("Kids"); +bool CPDF_Document::InsertDeletePDFPage( + RetainPtr<CPDF_Dictionary> pPages, + int nPagesToGo, + RetainPtr<CPDF_Dictionary> pPageDict, + bool bInsert, + std::set<RetainPtr<CPDF_Dictionary>>* pVisited) { + RetainPtr<CPDF_Array> pKidList = pPages->GetMutableArrayFor("Kids"); if (!pKidList) return false; for (size_t i = 0; i < pKidList->size(); i++) { - CPDF_Dictionary* pKid = pKidList->GetDictAt(i); - if (pKid->GetStringFor("Type") == "Page") { + RetainPtr<CPDF_Dictionary> pKid = pKidList->GetMutableDictAt(i); + if (pKid->GetNameFor("Type") == "Page") { if (nPagesToGo != 0) { nPagesToGo--; continue; @@ -403,13 +478,14 @@ nPagesToGo -= nPages; continue; } - if (pdfium::ContainsKey(*pVisited, pKid)) + if (pdfium::Contains(*pVisited, pKid)) return false; - pdfium::ScopedSetInsertion<CPDF_Dictionary*> insertion(pVisited, pKid); - if (!InsertDeletePDFPage(pKid, nPagesToGo, pPageDict, bInsert, pVisited)) + ScopedSetInsertion<RetainPtr<CPDF_Dictionary>> insertion(pVisited, pKid); + if (!InsertDeletePDFPage(std::move(pKid), nPagesToGo, pPageDict, bInsert, + pVisited)) { return false; - + } pPages->SetNewFor<CPDF_Number>( "Count", pPages->GetIntegerFor("Count") + (bInsert ? 1 : -1)); break; @@ -417,9 +493,13 @@ return true; } -bool CPDF_Document::InsertNewPage(int iPage, CPDF_Dictionary* pPageDict) { - CPDF_Dictionary* pRoot = GetRoot(); - CPDF_Dictionary* pPages = pRoot ? pRoot->GetDictFor("Pages") : nullptr; +bool CPDF_Document::InsertNewPage(int iPage, + RetainPtr<CPDF_Dictionary> pPageDict) { + RetainPtr<CPDF_Dictionary> pRoot = GetMutableRoot(); + if (!pRoot) + return false; + + RetainPtr<CPDF_Dictionary> pPages = pRoot->GetMutableDictFor("Pages"); if (!pPages) return false; @@ -428,37 +508,42 @@ return false; if (iPage == nPages) { - CPDF_Array* pPagesList = pPages->GetArrayFor("Kids"); - if (!pPagesList) - pPagesList = pPages->SetNewFor<CPDF_Array>("Kids"); - pPagesList->AddNew<CPDF_Reference>(this, pPageDict->GetObjNum()); + RetainPtr<CPDF_Array> pPagesList = pPages->GetOrCreateArrayFor("Kids"); + pPagesList->AppendNew<CPDF_Reference>(this, pPageDict->GetObjNum()); pPages->SetNewFor<CPDF_Number>("Count", nPages + 1); pPageDict->SetNewFor<CPDF_Reference>("Parent", this, pPages->GetObjNum()); ResetTraversal(); } else { - std::set<CPDF_Dictionary*> stack = {pPages}; - if (!InsertDeletePDFPage(pPages, iPage, pPageDict, true, &stack)) + std::set<RetainPtr<CPDF_Dictionary>> stack = {pPages}; + if (!InsertDeletePDFPage(std::move(pPages), iPage, pPageDict, true, &stack)) return false; } m_PageList.insert(m_PageList.begin() + iPage, pPageDict->GetObjNum()); return true; } -CPDF_Dictionary* CPDF_Document::GetInfo() { +RetainPtr<CPDF_Dictionary> CPDF_Document::GetInfo() { if (m_pInfoDict) - return m_pInfoDict.Get(); + return m_pInfoDict; - if (!m_pParser || !m_pParser->GetInfoObjNum()) + if (!m_pParser) return nullptr; - auto ref = - pdfium::MakeRetain<CPDF_Reference>(this, m_pParser->GetInfoObjNum()); - m_pInfoDict.Reset(ToDictionary(ref->GetDirect())); - return m_pInfoDict.Get(); + uint32_t info_obj_num = m_pParser->GetInfoObjNum(); + if (info_obj_num == 0) + return nullptr; + + auto ref = pdfium::MakeRetain<CPDF_Reference>(this, info_obj_num); + m_pInfoDict = ToDictionary(ref->GetMutableDirect()); + return m_pInfoDict; +} + +RetainPtr<const CPDF_Array> CPDF_Document::GetFileIdentifier() const { + return m_pParser ? m_pParser->GetIDArray() : nullptr; } void CPDF_Document::DeletePage(int iPage) { - CPDF_Dictionary* pPages = GetPagesDict(); + RetainPtr<CPDF_Dictionary> pPages = GetMutablePagesDict(); if (!pPages) return; @@ -466,13 +551,21 @@ if (iPage < 0 || iPage >= nPages) return; - std::set<CPDF_Dictionary*> stack = {pPages}; - if (!InsertDeletePDFPage(pPages, iPage, nullptr, false, &stack)) + std::set<RetainPtr<CPDF_Dictionary>> stack = {pPages}; + if (!InsertDeletePDFPage(std::move(pPages), iPage, nullptr, false, &stack)) return; m_PageList.erase(m_PageList.begin() + iPage); } +void CPDF_Document::SetRootForTesting(RetainPtr<CPDF_Dictionary> root) { + m_pRootDict = std::move(root); +} + +void CPDF_Document::ResizePageListForTesting(size_t size) { + m_PageList.resize(size); +} + CPDF_Document::StockFontClearer::StockFontClearer( CPDF_Document::PageDataIface* pPageData) : m_pPageData(pPageData) {}
diff --git a/core/fpdfapi/parser/cpdf_document.h b/core/fpdfapi/parser/cpdf_document.h index d0d1729..9ceff30 100644 --- a/core/fpdfapi/parser/cpdf_document.h +++ b/core/fpdfapi/parser/cpdf_document.h
@@ -1,4 +1,4 @@ -// Copyright 2016 PDFium Authors. All rights reserved. +// Copyright 2016 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -7,32 +7,23 @@ #ifndef CORE_FPDFAPI_PARSER_CPDF_DOCUMENT_H_ #define CORE_FPDFAPI_PARSER_CPDF_DOCUMENT_H_ -#include <functional> #include <memory> #include <set> #include <utility> #include <vector> -#include "build/build_config.h" -#include "core/fpdfapi/parser/cpdf_object.h" +#include "core/fpdfapi/parser/cpdf_dictionary.h" #include "core/fpdfapi/parser/cpdf_parser.h" +#include "core/fxcrt/fx_memory.h" #include "core/fxcrt/observed_ptr.h" #include "core/fxcrt/retain_ptr.h" #include "core/fxcrt/unowned_ptr.h" -class CFX_Matrix; -class CPDF_LinearizedHeader; -class CPDF_Object; class CPDF_ReadValidator; class CPDF_StreamAcc; class IFX_SeekableReadStream; class JBig2_DocumentContext; -#define FPDFPERM_MODIFY 0x0008 -#define FPDFPERM_ANNOT_FORM 0x0020 -#define FPDFPERM_FILL_FORM 0x0100 -#define FPDFPERM_EXTRACT_ACCESS 0x0200 - class CPDF_Document : public Observable, public CPDF_Parser::ParsedObjectsHolder { public: @@ -40,7 +31,6 @@ class Extension { public: virtual ~Extension() = default; - virtual CPDF_Document* GetPDFDoc() const = 0; virtual int GetPageCount() const = 0; virtual void DeletePage(int page_index) = 0; virtual uint32_t GetUserPermissions() const = 0; @@ -62,12 +52,15 @@ virtual void ClearStockFont() = 0; virtual RetainPtr<CPDF_StreamAcc> GetFontFileStreamAcc( - const CPDF_Stream* pFontStream) = 0; + RetainPtr<const CPDF_Stream> pFontStream) = 0; virtual void MaybePurgeFontFileStreamAcc( - const CPDF_Stream* pFontStream) = 0; + RetainPtr<CPDF_StreamAcc>&& pStreamAcc) = 0; + virtual void MaybePurgeImage(uint32_t objnum) = 0; void SetDocument(CPDF_Document* pDoc) { m_pDoc = pDoc; } - CPDF_Document* GetDocument() const { return m_pDoc.Get(); } + + protected: + CPDF_Document* GetDocument() const { return m_pDoc; } private: UnownedPtr<CPDF_Document> m_pDoc; @@ -79,13 +72,17 @@ virtual ~RenderDataIface(); void SetDocument(CPDF_Document* pDoc) { m_pDoc = pDoc; } - CPDF_Document* GetDocument() const { return m_pDoc.Get(); } + + protected: + CPDF_Document* GetDocument() const { return m_pDoc; } private: UnownedPtr<CPDF_Document> m_pDoc; }; - static const int kPageMaxNum = 0xFFFFF; + static constexpr int kPageMaxNum = 0xFFFFF; + + static bool IsValidPageObject(const CPDF_Object* obj); CPDF_Document(std::unique_ptr<RenderDataIface> pRenderData, std::unique_ptr<PageDataIface> pPageData); @@ -97,53 +94,73 @@ } CPDF_Parser* GetParser() const { return m_pParser.get(); } - CPDF_Dictionary* GetRoot() const { return m_pRootDict.Get(); } - CPDF_Dictionary* GetInfo(); + const CPDF_Dictionary* GetRoot() const { return m_pRootDict.Get(); } + RetainPtr<CPDF_Dictionary> GetMutableRoot() { return m_pRootDict; } + RetainPtr<CPDF_Dictionary> GetInfo(); + RetainPtr<const CPDF_Array> GetFileIdentifier() const; void DeletePage(int iPage); int GetPageCount() const; bool IsPageLoaded(int iPage) const; - CPDF_Dictionary* GetPageDictionary(int iPage); + RetainPtr<const CPDF_Dictionary> GetPageDictionary(int iPage); + RetainPtr<CPDF_Dictionary> GetMutablePageDictionary(int iPage); int GetPageIndex(uint32_t objnum); uint32_t GetUserPermissions() const; + // PageDataIface wrappers, try to avoid explicit getter calls. + RetainPtr<CPDF_StreamAcc> GetFontFileStreamAcc( + RetainPtr<const CPDF_Stream> pFontStream); + void MaybePurgeFontFileStreamAcc(RetainPtr<CPDF_StreamAcc>&& pStreamAcc); + void MaybePurgeImage(uint32_t objnum); + // Returns a valid pointer, unless it is called during destruction. PageDataIface* GetPageData() const { return m_pDocPage.get(); } RenderDataIface* GetRenderData() const { return m_pDocRender.get(); } void SetPageObjNum(int iPage, uint32_t objNum); - std::unique_ptr<JBig2_DocumentContext>* CodecContext() { - return &m_pCodecContext; - } + JBig2_DocumentContext* GetOrCreateCodecContext(); LinkListIface* GetLinksContext() const { return m_pLinksContext.get(); } void SetLinksContext(std::unique_ptr<LinkListIface> pContext) { m_pLinksContext = std::move(pContext); } - // CPDF_Parser::ParsedObjectsHolder overrides: - bool TryInit() override; + // Behaves like NewIndirect<CPDF_Stream>(), but keeps track of the new stream. + RetainPtr<CPDF_Stream> CreateModifiedAPStream(); - CPDF_Parser::Error LoadDoc( - const RetainPtr<IFX_SeekableReadStream>& pFileAccess, - const char* password); - CPDF_Parser::Error LoadLinearizedDoc( - const RetainPtr<CPDF_ReadValidator>& validator, - const char* password); + // Returns whether CreateModifiedAPStream() created `stream`. + bool IsModifiedAPStream(const CPDF_Stream* stream) const; + + // CPDF_Parser::ParsedObjectsHolder: + bool TryInit() override; + RetainPtr<CPDF_Object> ParseIndirectObject(uint32_t objnum) override; + + CPDF_Parser::Error LoadDoc(RetainPtr<IFX_SeekableReadStream> pFileAccess, + const ByteString& password); + CPDF_Parser::Error LoadLinearizedDoc(RetainPtr<CPDF_ReadValidator> validator, + const ByteString& password); bool has_valid_cross_reference_table() const { return m_bHasValidCrossReferenceTable; } void LoadPages(); void CreateNewDoc(); - CPDF_Dictionary* CreateNewPage(int iPage); + RetainPtr<CPDF_Dictionary> CreateNewPage(int iPage); void IncrementParsedPageCount() { ++m_ParsedPageCount; } uint32_t GetParsedPageCountForTesting() { return m_ParsedPageCount; } protected: + void SetParser(std::unique_ptr<CPDF_Parser> pParser); + + void SetRootForTesting(RetainPtr<CPDF_Dictionary> root); + void ResizePageListForTesting(size_t size); + + private: class StockFontClearer { public: + FX_STACK_ALLOCATED(); + explicit StockFontClearer(CPDF_Document::PageDataIface* pPageData); ~StockFontClearer(); @@ -153,24 +170,23 @@ // Retrieve page count information by getting count value from the tree nodes int RetrievePageCount(); + // When this method is called, m_pTreeTraversal[level] exists. - CPDF_Dictionary* TraversePDFPages(int iPage, int* nPagesToGo, size_t level); - int FindPageIndex(const CPDF_Dictionary* pNode, - uint32_t* skip_count, - uint32_t objnum, - int* index, - int level) const; - RetainPtr<CPDF_Object> ParseIndirectObject(uint32_t objnum) override; - const CPDF_Dictionary* GetPagesDict() const; - CPDF_Dictionary* GetPagesDict(); - bool InsertDeletePDFPage(CPDF_Dictionary* pPages, + RetainPtr<CPDF_Dictionary> TraversePDFPages(int iPage, + int* nPagesToGo, + size_t level); + + RetainPtr<const CPDF_Dictionary> GetPagesDict() const; + RetainPtr<CPDF_Dictionary> GetMutablePagesDict(); + + bool InsertDeletePDFPage(RetainPtr<CPDF_Dictionary> pPages, int nPagesToGo, - CPDF_Dictionary* pPageDict, + RetainPtr<CPDF_Dictionary> pPageDict, bool bInsert, - std::set<CPDF_Dictionary*>* pVisited); - bool InsertNewPage(int iPage, CPDF_Dictionary* pPageDict); + std::set<RetainPtr<CPDF_Dictionary>>* pVisited); + + bool InsertNewPage(int iPage, RetainPtr<CPDF_Dictionary> pPageDict); void ResetTraversal(); - void SetParser(std::unique_ptr<CPDF_Parser> pParser); CPDF_Parser::Error HandleLoadResult(CPDF_Parser::Error error); std::unique_ptr<CPDF_Parser> m_pParser; @@ -181,7 +197,7 @@ // vector corresponds to the level being described. The pair contains a // pointer to the dictionary being processed at the level, and an index of the // of the child being processed within the dictionary's /Kids array. - std::vector<std::pair<CPDF_Dictionary*, size_t>> m_pTreeTraversal; + std::vector<std::pair<RetainPtr<CPDF_Dictionary>, size_t>> m_pTreeTraversal; // True if the CPDF_Parser succeeded without having to rebuild the cross // reference table. @@ -196,6 +212,7 @@ std::unique_ptr<PageDataIface> m_pDocPage; // Must be after |m_pDocRender|. std::unique_ptr<JBig2_DocumentContext> m_pCodecContext; std::unique_ptr<LinkListIface> m_pLinksContext; + std::set<uint32_t> m_ModifiedAPStreamIDs; std::vector<uint32_t> m_PageList; // Page number to page's dict objnum. // Must be second to last.
diff --git a/core/fpdfapi/parser/cpdf_document_unittest.cpp b/core/fpdfapi/parser/cpdf_document_unittest.cpp index 1c52e51..bc2aaae 100644 --- a/core/fpdfapi/parser/cpdf_document_unittest.cpp +++ b/core/fpdfapi/parser/cpdf_document_unittest.cpp
@@ -1,4 +1,4 @@ -// Copyright 2016 PDFium Authors. All rights reserved. +// Copyright 2016 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -7,8 +7,7 @@ #include <memory> #include <utility> -#include "core/fpdfapi/page/cpdf_docpagedata.h" -#include "core/fpdfapi/page/cpdf_pagemodule.h" +#include "core/fpdfapi/page/test_with_page_module.h" #include "core/fpdfapi/parser/cpdf_array.h" #include "core/fpdfapi/parser/cpdf_boolean.h" #include "core/fpdfapi/parser/cpdf_dictionary.h" @@ -18,115 +17,114 @@ #include "core/fpdfapi/parser/cpdf_parser.h" #include "core/fpdfapi/parser/cpdf_reference.h" #include "core/fpdfapi/parser/cpdf_string.h" -#include "core/fpdfapi/render/cpdf_docrenderdata.h" +#include "core/fpdfapi/parser/cpdf_test_document.h" #include "testing/gtest/include/gtest/gtest.h" -#include "third_party/base/ptr_util.h" +#include "third_party/base/check.h" namespace { const int kNumTestPages = 7; -CPDF_Dictionary* CreatePageTreeNode(RetainPtr<CPDF_Array> kids, - CPDF_Document* pDoc, - int count) { - CPDF_Array* pUnowned = pDoc->AddIndirectObject(std::move(kids))->AsArray(); - CPDF_Dictionary* pageNode = pDoc->NewIndirect<CPDF_Dictionary>(); - pageNode->SetNewFor<CPDF_String>("Type", "Pages", false); - pageNode->SetNewFor<CPDF_Reference>("Kids", pDoc, pUnowned->GetObjNum()); +RetainPtr<CPDF_Dictionary> CreatePageTreeNode(RetainPtr<CPDF_Array> kids, + CPDF_Document* pDoc, + int count) { + uint32_t new_objnum = pDoc->AddIndirectObject(kids); + auto pageNode = pDoc->NewIndirect<CPDF_Dictionary>(); + pageNode->SetNewFor<CPDF_Name>("Type", "Pages"); + pageNode->SetNewFor<CPDF_Reference>("Kids", pDoc, new_objnum); pageNode->SetNewFor<CPDF_Number>("Count", count); - for (size_t i = 0; i < pUnowned->size(); i++) { - pUnowned->GetDictAt(i)->SetNewFor<CPDF_Reference>("Parent", pDoc, - pageNode->GetObjNum()); + for (size_t i = 0; i < kids->size(); i++) { + kids->GetMutableDictAt(i)->SetNewFor<CPDF_Reference>("Parent", pDoc, + pageNode->GetObjNum()); } return pageNode; } RetainPtr<CPDF_Dictionary> CreateNumberedPage(size_t number) { auto page = pdfium::MakeRetain<CPDF_Dictionary>(); - page->SetNewFor<CPDF_String>("Type", "Page", false); + page->SetNewFor<CPDF_Name>("Type", "Page"); page->SetNewFor<CPDF_Number>("PageNumbering", static_cast<int>(number)); return page; } -class CPDF_TestDocumentForPages final : public CPDF_Document { +class CPDF_TestDocumentForPages final : public CPDF_TestDocument { public: - CPDF_TestDocumentForPages() - : CPDF_Document(pdfium::MakeUnique<CPDF_DocRenderData>(), - pdfium::MakeUnique<CPDF_DocPageData>()) { + CPDF_TestDocumentForPages() { // Set up test auto zeroToTwo = pdfium::MakeRetain<CPDF_Array>(); - zeroToTwo->AddNew<CPDF_Reference>( - this, AddIndirectObject(CreateNumberedPage(0))->GetObjNum()); - zeroToTwo->AddNew<CPDF_Reference>( - this, AddIndirectObject(CreateNumberedPage(1))->GetObjNum()); - zeroToTwo->AddNew<CPDF_Reference>( - this, AddIndirectObject(CreateNumberedPage(2))->GetObjNum()); - CPDF_Dictionary* branch1 = + zeroToTwo->AppendNew<CPDF_Reference>( + this, AddIndirectObject(CreateNumberedPage(0))); + zeroToTwo->AppendNew<CPDF_Reference>( + this, AddIndirectObject(CreateNumberedPage(1))); + zeroToTwo->AppendNew<CPDF_Reference>( + this, AddIndirectObject(CreateNumberedPage(2))); + RetainPtr<CPDF_Dictionary> branch1 = CreatePageTreeNode(std::move(zeroToTwo), this, 3); auto zeroToThree = pdfium::MakeRetain<CPDF_Array>(); - zeroToThree->AddNew<CPDF_Reference>(this, branch1->GetObjNum()); - zeroToThree->AddNew<CPDF_Reference>( - this, AddIndirectObject(CreateNumberedPage(3))->GetObjNum()); - CPDF_Dictionary* branch2 = + zeroToThree->AppendNew<CPDF_Reference>(this, branch1->GetObjNum()); + zeroToThree->AppendNew<CPDF_Reference>( + this, AddIndirectObject(CreateNumberedPage(3))); + RetainPtr<CPDF_Dictionary> branch2 = CreatePageTreeNode(std::move(zeroToThree), this, 4); auto fourFive = pdfium::MakeRetain<CPDF_Array>(); - fourFive->AddNew<CPDF_Reference>( - this, AddIndirectObject(CreateNumberedPage(4))->GetObjNum()); - fourFive->AddNew<CPDF_Reference>( - this, AddIndirectObject(CreateNumberedPage(5))->GetObjNum()); - CPDF_Dictionary* branch3 = CreatePageTreeNode(std::move(fourFive), this, 2); + fourFive->AppendNew<CPDF_Reference>( + this, AddIndirectObject(CreateNumberedPage(4))); + fourFive->AppendNew<CPDF_Reference>( + this, AddIndirectObject(CreateNumberedPage(5))); + RetainPtr<CPDF_Dictionary> branch3 = + CreatePageTreeNode(std::move(fourFive), this, 2); auto justSix = pdfium::MakeRetain<CPDF_Array>(); - justSix->AddNew<CPDF_Reference>( - this, AddIndirectObject(CreateNumberedPage(6))->GetObjNum()); - CPDF_Dictionary* branch4 = CreatePageTreeNode(std::move(justSix), this, 1); + justSix->AppendNew<CPDF_Reference>( + this, AddIndirectObject(CreateNumberedPage(6))); + RetainPtr<CPDF_Dictionary> branch4 = + CreatePageTreeNode(std::move(justSix), this, 1); auto allPages = pdfium::MakeRetain<CPDF_Array>(); - allPages->AddNew<CPDF_Reference>(this, branch2->GetObjNum()); - allPages->AddNew<CPDF_Reference>(this, branch3->GetObjNum()); - allPages->AddNew<CPDF_Reference>(this, branch4->GetObjNum()); - CPDF_Dictionary* pagesDict = + allPages->AppendNew<CPDF_Reference>(this, branch2->GetObjNum()); + allPages->AppendNew<CPDF_Reference>(this, branch3->GetObjNum()); + allPages->AppendNew<CPDF_Reference>(this, branch4->GetObjNum()); + RetainPtr<CPDF_Dictionary> pagesDict = CreatePageTreeNode(std::move(allPages), this, kNumTestPages); - m_pRootDict.Reset(NewIndirect<CPDF_Dictionary>()); - m_pRootDict->SetNewFor<CPDF_Reference>("Pages", this, - pagesDict->GetObjNum()); - m_PageList.resize(kNumTestPages); + SetRootForTesting(NewIndirect<CPDF_Dictionary>()); + GetMutableRoot()->SetNewFor<CPDF_Reference>("Pages", this, + pagesDict->GetObjNum()); + ResizePageListForTesting(kNumTestPages); } void SetTreeSize(int size) { - m_pRootDict->SetNewFor<CPDF_Number>("Count", size); - m_PageList.resize(size); + GetMutableRoot()->SetNewFor<CPDF_Number>("Count", size); + ResizePageListForTesting(size); } }; -class CPDF_TestDocumentWithPageWithoutPageNum final : public CPDF_Document { +class CPDF_TestDocumentWithPageWithoutPageNum final : public CPDF_TestDocument { public: - CPDF_TestDocumentWithPageWithoutPageNum() - : CPDF_Document(pdfium::MakeUnique<CPDF_DocRenderData>(), - pdfium::MakeUnique<CPDF_DocPageData>()) { + CPDF_TestDocumentWithPageWithoutPageNum() { // Set up test auto allPages = pdfium::MakeRetain<CPDF_Array>(); - allPages->AddNew<CPDF_Reference>( - this, AddIndirectObject(CreateNumberedPage(0))->GetObjNum()); - allPages->AddNew<CPDF_Reference>( - this, AddIndirectObject(CreateNumberedPage(1))->GetObjNum()); + allPages->AppendNew<CPDF_Reference>( + this, AddIndirectObject(CreateNumberedPage(0))); + allPages->AppendNew<CPDF_Reference>( + this, AddIndirectObject(CreateNumberedPage(1))); // Page without pageNum. - inlined_page_ = allPages->Add(CreateNumberedPage(2)); - CPDF_Dictionary* pagesDict = + inlined_page_ = CreateNumberedPage(2); + allPages->Append(inlined_page_); + RetainPtr<CPDF_Dictionary> pagesDict = CreatePageTreeNode(std::move(allPages), this, 3); - m_pRootDict.Reset(NewIndirect<CPDF_Dictionary>()); - m_pRootDict->SetNewFor<CPDF_Reference>("Pages", this, - pagesDict->GetObjNum()); - m_PageList.resize(3); + SetRootForTesting(NewIndirect<CPDF_Dictionary>()); + GetMutableRoot()->SetNewFor<CPDF_Reference>("Pages", this, + pagesDict->GetObjNum()); + ResizePageListForTesting(3); } - const CPDF_Object* inlined_page() const { return inlined_page_; } + const CPDF_Object* inlined_page() const { return inlined_page_.Get(); } private: - const CPDF_Object* inlined_page_; + RetainPtr<CPDF_Object> inlined_page_; }; class TestLinearized final : public CPDF_LinearizedHeader { @@ -135,80 +133,75 @@ : CPDF_LinearizedHeader(dict, 0) {} }; -class CPDF_TestDocPagesWithoutKids final : public CPDF_Document { +class CPDF_TestDocPagesWithoutKids final : public CPDF_TestDocument { public: - CPDF_TestDocPagesWithoutKids() - : CPDF_Document(pdfium::MakeUnique<CPDF_DocRenderData>(), - pdfium::MakeUnique<CPDF_DocPageData>()) { - CPDF_Dictionary* pagesDict = NewIndirect<CPDF_Dictionary>(); + CPDF_TestDocPagesWithoutKids() { + auto pagesDict = NewIndirect<CPDF_Dictionary>(); pagesDict->SetNewFor<CPDF_Name>("Type", "Pages"); pagesDict->SetNewFor<CPDF_Number>("Count", 3); - m_PageList.resize(10); - m_pRootDict.Reset(NewIndirect<CPDF_Dictionary>()); - m_pRootDict->SetNewFor<CPDF_Reference>("Pages", this, - pagesDict->GetObjNum()); + ResizePageListForTesting(10); + SetRootForTesting(NewIndirect<CPDF_Dictionary>()); + GetMutableRoot()->SetNewFor<CPDF_Reference>("Pages", this, + pagesDict->GetObjNum()); } }; -class CPDF_TestDocumentAllowSetParser final : public CPDF_Document { +class CPDF_TestDocumentAllowSetParser final : public CPDF_TestDocument { public: - CPDF_TestDocumentAllowSetParser() - : CPDF_Document(pdfium::MakeUnique<CPDF_DocRenderData>(), - pdfium::MakeUnique<CPDF_DocPageData>()) {} + CPDF_TestDocumentAllowSetParser() = default; using CPDF_Document::SetParser; }; } // namespace -class cpdf_document_test : public testing::Test { - public: - void SetUp() override { CPDF_PageModule::Create(); } - void TearDown() override { CPDF_PageModule::Destroy(); } -}; +using DocumentTest = TestWithPageModule; -TEST_F(cpdf_document_test, GetPages) { +TEST_F(DocumentTest, GetPages) { std::unique_ptr<CPDF_TestDocumentForPages> document = - pdfium::MakeUnique<CPDF_TestDocumentForPages>(); + std::make_unique<CPDF_TestDocumentForPages>(); for (int i = 0; i < kNumTestPages; i++) { - CPDF_Dictionary* page = document->GetPageDictionary(i); + RetainPtr<const CPDF_Dictionary> page = document->GetPageDictionary(i); ASSERT_TRUE(page); ASSERT_TRUE(page->KeyExist("PageNumbering")); EXPECT_EQ(i, page->GetIntegerFor("PageNumbering")); } - CPDF_Dictionary* page = document->GetPageDictionary(kNumTestPages); + RetainPtr<const CPDF_Dictionary> page = + document->GetPageDictionary(kNumTestPages); EXPECT_FALSE(page); } -TEST_F(cpdf_document_test, GetPageWithoutObjNumTwice) { - auto document = pdfium::MakeUnique<CPDF_TestDocumentWithPageWithoutPageNum>(); - CPDF_Dictionary* page = document->GetPageDictionary(2); +TEST_F(DocumentTest, GetPageWithoutObjNumTwice) { + auto document = std::make_unique<CPDF_TestDocumentWithPageWithoutPageNum>(); + RetainPtr<const CPDF_Dictionary> page = document->GetPageDictionary(2); ASSERT_TRUE(page); ASSERT_EQ(document->inlined_page(), page); - CPDF_Dictionary* second_call_page = document->GetPageDictionary(2); + RetainPtr<const CPDF_Dictionary> second_call_page = + document->GetPageDictionary(2); EXPECT_TRUE(second_call_page); EXPECT_EQ(page, second_call_page); } -TEST_F(cpdf_document_test, GetPagesReverseOrder) { +TEST_F(DocumentTest, GetPagesReverseOrder) { std::unique_ptr<CPDF_TestDocumentForPages> document = - pdfium::MakeUnique<CPDF_TestDocumentForPages>(); + std::make_unique<CPDF_TestDocumentForPages>(); for (int i = 6; i >= 0; i--) { - CPDF_Dictionary* page = document->GetPageDictionary(i); + RetainPtr<const CPDF_Dictionary> page = document->GetPageDictionary(i); ASSERT_TRUE(page); ASSERT_TRUE(page->KeyExist("PageNumbering")); EXPECT_EQ(i, page->GetIntegerFor("PageNumbering")); } - CPDF_Dictionary* page = document->GetPageDictionary(kNumTestPages); + RetainPtr<const CPDF_Dictionary> page = + document->GetPageDictionary(kNumTestPages); EXPECT_FALSE(page); } -TEST_F(cpdf_document_test, GetPagesInDisorder) { +TEST_F(DocumentTest, GetPagesInDisorder) { std::unique_ptr<CPDF_TestDocumentForPages> document = - pdfium::MakeUnique<CPDF_TestDocumentForPages>(); + std::make_unique<CPDF_TestDocumentForPages>(); - CPDF_Dictionary* page = document->GetPageDictionary(1); + RetainPtr<const CPDF_Dictionary> page = document->GetPageDictionary(1); ASSERT_TRUE(page); ASSERT_TRUE(page->KeyExist("PageNumbering")); EXPECT_EQ(1, page->GetIntegerFor("PageNumbering")); @@ -227,36 +220,72 @@ EXPECT_EQ(6, page->GetIntegerFor("PageNumbering")); } -TEST_F(cpdf_document_test, UseCachedPageObjNumIfHaveNotPagesDict) { - // ObjNum can be added in CPDF_DataAvail::IsPageAvail, and PagesDict - // can be not exists in this case. - // (case, when hint table is used to page check in CPDF_DataAvail). - auto dict = pdfium::MakeRetain<CPDF_Dictionary>(); - dict->SetNewFor<CPDF_Boolean>("Linearized", true); - const int page_count = 100; - dict->SetNewFor<CPDF_Number>("N", page_count); - auto linearized = pdfium::MakeUnique<TestLinearized>(dict.Get()); - auto parser = pdfium::MakeUnique<CPDF_Parser>(); - parser->SetLinearizedHeader(std::move(linearized)); - CPDF_TestDocumentAllowSetParser document; - document.SetParser(std::move(parser)); - document.LoadPages(); - ASSERT_EQ(page_count, document.GetPageCount()); - CPDF_Object* page_stub = document.NewIndirect<CPDF_Dictionary>(); - const uint32_t obj_num = page_stub->GetObjNum(); - const int test_page_num = 33; +TEST_F(DocumentTest, IsValidPageObject) { + CPDF_TestDocumentForPages document; - EXPECT_FALSE(document.IsPageLoaded(test_page_num)); - EXPECT_EQ(nullptr, document.GetPageDictionary(test_page_num)); + auto dict_type_name_page = pdfium::MakeRetain<CPDF_Dictionary>(); + dict_type_name_page->SetNewFor<CPDF_Name>("Type", "Page"); + document.AddIndirectObject(dict_type_name_page); + EXPECT_TRUE(CPDF_Document::IsValidPageObject(dict_type_name_page.Get())); - document.SetPageObjNum(test_page_num, obj_num); - EXPECT_TRUE(document.IsPageLoaded(test_page_num)); - EXPECT_EQ(page_stub, document.GetPageDictionary(test_page_num)); + auto dict_type_string_page = pdfium::MakeRetain<CPDF_Dictionary>(); + dict_type_string_page->SetNewFor<CPDF_String>("Type", "Page", false); + document.AddIndirectObject(dict_type_string_page); + EXPECT_FALSE(CPDF_Document::IsValidPageObject(dict_type_string_page.Get())); + + auto dict_type_name_font = pdfium::MakeRetain<CPDF_Dictionary>(); + dict_type_name_font->SetNewFor<CPDF_Name>("Type", "Font"); + document.AddIndirectObject(dict_type_name_font); + EXPECT_FALSE(CPDF_Document::IsValidPageObject(dict_type_name_font.Get())); + + auto obj_no_type = document.NewIndirect<CPDF_Dictionary>(); + EXPECT_FALSE(CPDF_Document::IsValidPageObject(obj_no_type.Get())); } -TEST_F(cpdf_document_test, CountGreaterThanPageTree) { +TEST_F(DocumentTest, UseCachedPageObjNumIfHaveNotPagesDict) { + // ObjNum can be added in CPDF_DataAvail::IsPageAvail(), and PagesDict may not + // exist in this case, e.g. when hint table is used to page check in + // CPDF_DataAvail. + constexpr int kPageCount = 100; + constexpr int kTestPageNum = 33; + + auto linearization_dict = pdfium::MakeRetain<CPDF_Dictionary>(); + CPDF_TestDocumentAllowSetParser document; + + { + auto first_page = CreateNumberedPage(0); + ASSERT_TRUE(first_page); + + int first_page_obj_num = document.AddIndirectObject(first_page); + ASSERT_NE(kTestPageNum, first_page_obj_num); + + linearization_dict->SetNewFor<CPDF_Boolean>("Linearized", true); + linearization_dict->SetNewFor<CPDF_Number>("N", kPageCount); + linearization_dict->SetNewFor<CPDF_Number>("O", first_page_obj_num); + + auto parser = std::make_unique<CPDF_Parser>(); + parser->SetLinearizedHeaderForTesting( + std::make_unique<TestLinearized>(linearization_dict.Get())); + document.SetParser(std::move(parser)); + } + + document.LoadPages(); + + ASSERT_EQ(kPageCount, document.GetPageCount()); + auto page_stub = document.NewIndirect<CPDF_Dictionary>(); + const uint32_t obj_num = page_stub->GetObjNum(); + + EXPECT_FALSE(document.IsPageLoaded(kTestPageNum)); + EXPECT_FALSE(document.GetPageDictionary(kTestPageNum)); + + document.SetPageObjNum(kTestPageNum, obj_num); + EXPECT_TRUE(document.IsPageLoaded(kTestPageNum)); + EXPECT_EQ(page_stub, document.GetPageDictionary(kTestPageNum)); +} + +TEST_F(DocumentTest, CountGreaterThanPageTree) { std::unique_ptr<CPDF_TestDocumentForPages> document = - pdfium::MakeUnique<CPDF_TestDocumentForPages>(); + std::make_unique<CPDF_TestDocumentForPages>(); document->SetTreeSize(kNumTestPages + 3); for (int i = 0; i < kNumTestPages; i++) EXPECT_TRUE(document->GetPageDictionary(i)); @@ -265,9 +294,9 @@ EXPECT_TRUE(document->GetPageDictionary(kNumTestPages - 1)); } -TEST_F(cpdf_document_test, PagesWithoutKids) { +TEST_F(DocumentTest, PagesWithoutKids) { // Set up a document with Pages dict without kids, and Count = 3 - auto pDoc = pdfium::MakeUnique<CPDF_TestDocPagesWithoutKids>(); + auto pDoc = std::make_unique<CPDF_TestDocPagesWithoutKids>(); EXPECT_TRUE(pDoc->GetPageDictionary(0)); // Test GetPage does not fetch pages out of range for (int i = 1; i < 5; i++)
diff --git a/core/fpdfapi/parser/cpdf_encryptor.cpp b/core/fpdfapi/parser/cpdf_encryptor.cpp index 706d668..e1804fc 100644 --- a/core/fpdfapi/parser/cpdf_encryptor.cpp +++ b/core/fpdfapi/parser/cpdf_encryptor.cpp
@@ -1,4 +1,4 @@ -// Copyright 2017 PDFium Authors. All rights reserved. +// Copyright 2017 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -6,20 +6,24 @@ #include "core/fpdfapi/parser/cpdf_encryptor.h" -#include "core/fpdfapi/parser/cpdf_crypto_handler.h" +#include <stdint.h> -CPDF_Encryptor::CPDF_Encryptor(CPDF_CryptoHandler* pHandler, int objnum) +#include "core/fpdfapi/parser/cpdf_crypto_handler.h" +#include "core/fxcrt/data_vector.h" +#include "third_party/base/check.h" + +CPDF_Encryptor::CPDF_Encryptor(const CPDF_CryptoHandler* pHandler, int objnum) : m_pHandler(pHandler), m_ObjNum(objnum) { - ASSERT(m_pHandler); + DCHECK(m_pHandler); } -std::vector<uint8_t> CPDF_Encryptor::Encrypt( +DataVector<uint8_t> CPDF_Encryptor::Encrypt( pdfium::span<const uint8_t> src_data) const { if (src_data.empty()) - return std::vector<uint8_t>(); + return DataVector<uint8_t>(); - std::vector<uint8_t> result; - uint32_t buf_size = m_pHandler->EncryptGetSize(src_data); + DataVector<uint8_t> result; + size_t buf_size = m_pHandler->EncryptGetSize(src_data); result.resize(buf_size); m_pHandler->EncryptContent(m_ObjNum, 0, src_data, result.data(), buf_size); // Updates |buf_size| with actual. @@ -27,4 +31,4 @@ return result; } -CPDF_Encryptor::~CPDF_Encryptor() {} +CPDF_Encryptor::~CPDF_Encryptor() = default;
diff --git a/core/fpdfapi/parser/cpdf_encryptor.h b/core/fpdfapi/parser/cpdf_encryptor.h index cea737a..37f0763 100644 --- a/core/fpdfapi/parser/cpdf_encryptor.h +++ b/core/fpdfapi/parser/cpdf_encryptor.h
@@ -1,4 +1,4 @@ -// Copyright 2017 PDFium Authors. All rights reserved. +// Copyright 2017 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -9,8 +9,7 @@ #include <stdint.h> -#include <vector> - +#include "core/fxcrt/data_vector.h" #include "core/fxcrt/unowned_ptr.h" #include "third_party/base/span.h" @@ -18,13 +17,13 @@ class CPDF_Encryptor { public: - CPDF_Encryptor(CPDF_CryptoHandler* pHandler, int objnum); + CPDF_Encryptor(const CPDF_CryptoHandler* pHandler, int objnum); ~CPDF_Encryptor(); - std::vector<uint8_t> Encrypt(pdfium::span<const uint8_t> src_data) const; + DataVector<uint8_t> Encrypt(pdfium::span<const uint8_t> src_data) const; private: - UnownedPtr<CPDF_CryptoHandler> const m_pHandler; + UnownedPtr<const CPDF_CryptoHandler> const m_pHandler; const int m_ObjNum; };
diff --git a/core/fpdfapi/parser/cpdf_flateencoder.cpp b/core/fpdfapi/parser/cpdf_flateencoder.cpp index b685822..64acd72 100644 --- a/core/fpdfapi/parser/cpdf_flateencoder.cpp +++ b/core/fpdfapi/parser/cpdf_flateencoder.cpp
@@ -1,4 +1,4 @@ -// Copyright 2017 PDFium Authors. All rights reserved. +// Copyright 2017 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -6,9 +6,6 @@ #include "core/fpdfapi/parser/cpdf_flateencoder.h" -#include <memory> -#include <utility> - #include "constants/stream_dict_common.h" #include "core/fpdfapi/parser/cpdf_dictionary.h" #include "core/fpdfapi/parser/cpdf_name.h" @@ -16,10 +13,12 @@ #include "core/fpdfapi/parser/cpdf_stream.h" #include "core/fpdfapi/parser/cpdf_stream_acc.h" #include "core/fpdfapi/parser/fpdf_parser_decode.h" +#include "third_party/base/check.h" +#include "third_party/base/numerics/safe_conversions.h" -CPDF_FlateEncoder::CPDF_FlateEncoder(const CPDF_Stream* pStream, +CPDF_FlateEncoder::CPDF_FlateEncoder(RetainPtr<const CPDF_Stream> pStream, bool bFlateEncode) - : m_pAcc(pdfium::MakeRetain<CPDF_StreamAcc>(pStream)), m_dwSize(0) { + : m_pAcc(pdfium::MakeRetain<CPDF_StreamAcc>(pStream)) { m_pAcc->LoadAllDataRaw(); bool bHasFilter = pStream->HasFilter(); @@ -27,56 +26,59 @@ auto pDestAcc = pdfium::MakeRetain<CPDF_StreamAcc>(pStream); pDestAcc->LoadAllDataFiltered(); - m_dwSize = pDestAcc->GetSize(); - m_pData = pDestAcc->DetachData(); + m_Data = m_pAcc->GetSpan(); m_pClonedDict = ToDictionary(pStream->GetDict()->Clone()); m_pClonedDict->RemoveFor("Filter"); - ASSERT(!m_pDict); + DCHECK(!m_pDict); return; } if (bHasFilter || !bFlateEncode) { - m_pData = m_pAcc->GetData(); - m_dwSize = m_pAcc->GetSize(); - m_pDict.Reset(pStream->GetDict()); - ASSERT(!m_pClonedDict); + m_Data = m_pAcc->GetSpan(); + m_pDict = pStream->GetDict(); + DCHECK(!m_pClonedDict); return; } - // TODO(thestig): Move to Init() and check return value. - std::unique_ptr<uint8_t, FxFreeDeleter> buffer; - ::FlateEncode(m_pAcc->GetSpan(), &buffer, &m_dwSize); - - m_pData = std::move(buffer); + // TODO(thestig): Move to Init() and check for empty return value? + m_Data = ::FlateEncode(m_pAcc->GetSpan()); m_pClonedDict = ToDictionary(pStream->GetDict()->Clone()); - m_pClonedDict->SetNewFor<CPDF_Number>("Length", static_cast<int>(m_dwSize)); + m_pClonedDict->SetNewFor<CPDF_Number>( + "Length", pdfium::base::checked_cast<int>(GetSpan().size())); m_pClonedDict->SetNewFor<CPDF_Name>("Filter", "FlateDecode"); m_pClonedDict->RemoveFor(pdfium::stream::kDecodeParms); - ASSERT(!m_pDict); + DCHECK(!m_pDict); } -CPDF_FlateEncoder::~CPDF_FlateEncoder() {} +CPDF_FlateEncoder::~CPDF_FlateEncoder() = default; -void CPDF_FlateEncoder::CloneDict() { - if (m_pClonedDict) { - ASSERT(!m_pDict); +void CPDF_FlateEncoder::UpdateLength(size_t size) { + if (static_cast<size_t>(GetDict()->GetIntegerFor("Length")) == size) return; - } - m_pClonedDict = ToDictionary(m_pDict->Clone()); - ASSERT(m_pClonedDict); - m_pDict.Reset(); + if (!m_pClonedDict) { + m_pClonedDict = ToDictionary(m_pDict->Clone()); + m_pDict.Reset(); + } + DCHECK(m_pClonedDict); + DCHECK(!m_pDict); + m_pClonedDict->SetNewFor<CPDF_Number>("Length", static_cast<int>(size)); } -CPDF_Dictionary* CPDF_FlateEncoder::GetClonedDict() { - ASSERT(!m_pDict); - return m_pClonedDict.Get(); +bool CPDF_FlateEncoder::WriteDictTo(IFX_ArchiveStream* archive, + const CPDF_Encryptor* encryptor) const { + return GetDict()->WriteTo(archive, encryptor); } const CPDF_Dictionary* CPDF_FlateEncoder::GetDict() const { if (m_pClonedDict) { - ASSERT(!m_pDict); + DCHECK(!m_pDict); return m_pClonedDict.Get(); } - return m_pDict.Get(); } + +pdfium::span<const uint8_t> CPDF_FlateEncoder::GetSpan() const { + if (is_owned()) + return absl::get<DataVector<uint8_t>>(m_Data); + return absl::get<pdfium::span<const uint8_t>>(m_Data); +}
diff --git a/core/fpdfapi/parser/cpdf_flateencoder.h b/core/fpdfapi/parser/cpdf_flateencoder.h index df0db82..2d26d9b 100644 --- a/core/fpdfapi/parser/cpdf_flateencoder.h +++ b/core/fpdfapi/parser/cpdf_flateencoder.h
@@ -1,4 +1,4 @@ -// Copyright 2017 PDFium Authors. All rights reserved. +// Copyright 2017 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -7,37 +7,42 @@ #ifndef CORE_FPDFAPI_PARSER_CPDF_FLATEENCODER_H_ #define CORE_FPDFAPI_PARSER_CPDF_FLATEENCODER_H_ -#include <memory> +#include <stdint.h> -#include "core/fxcrt/fx_memory_wrappers.h" -#include "core/fxcrt/maybe_owned.h" +#include "core/fxcrt/data_vector.h" #include "core/fxcrt/retain_ptr.h" +#include "third_party/abseil-cpp/absl/types/variant.h" #include "third_party/base/span.h" class CPDF_Dictionary; +class CPDF_Encryptor; class CPDF_Stream; class CPDF_StreamAcc; +class IFX_ArchiveStream; class CPDF_FlateEncoder { public: - CPDF_FlateEncoder(const CPDF_Stream* pStream, bool bFlateEncode); + CPDF_FlateEncoder(RetainPtr<const CPDF_Stream> pStream, bool bFlateEncode); ~CPDF_FlateEncoder(); - void CloneDict(); - CPDF_Dictionary* GetClonedDict(); + void UpdateLength(size_t size); + bool WriteDictTo(IFX_ArchiveStream* archive, + const CPDF_Encryptor* encryptor) const; + + pdfium::span<const uint8_t> GetSpan() const; + + private: + bool is_owned() const { + return absl::holds_alternative<DataVector<uint8_t>>(m_Data); + } // Returns |m_pClonedDict| if it is valid. Otherwise returns |m_pDict|. const CPDF_Dictionary* GetDict() const; - pdfium::span<const uint8_t> GetSpan() const { - return pdfium::make_span(m_pData.Get(), m_dwSize); - } + // Must outlive `m_Data`. + RetainPtr<CPDF_StreamAcc> const m_pAcc; - private: - RetainPtr<CPDF_StreamAcc> m_pAcc; - - uint32_t m_dwSize; - MaybeOwned<uint8_t, FxFreeDeleter> m_pData; + absl::variant<pdfium::span<const uint8_t>, DataVector<uint8_t>> m_Data; // Only one of these two pointers is valid at any time. RetainPtr<const CPDF_Dictionary> m_pDict;
diff --git a/core/fpdfapi/parser/cpdf_hint_tables.cpp b/core/fpdfapi/parser/cpdf_hint_tables.cpp index e051254..ba3173d 100644 --- a/core/fpdfapi/parser/cpdf_hint_tables.cpp +++ b/core/fpdfapi/parser/cpdf_hint_tables.cpp
@@ -1,4 +1,4 @@ -// Copyright 2016 PDFium Authors. All rights reserved. +// Copyright 2016 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -13,14 +13,15 @@ #include "core/fpdfapi/parser/cpdf_dictionary.h" #include "core/fpdfapi/parser/cpdf_document.h" #include "core/fpdfapi/parser/cpdf_linearized_header.h" +#include "core/fpdfapi/parser/cpdf_parser.h" #include "core/fpdfapi/parser/cpdf_read_validator.h" #include "core/fpdfapi/parser/cpdf_stream.h" #include "core/fpdfapi/parser/cpdf_stream_acc.h" #include "core/fpdfapi/parser/cpdf_syntax_parser.h" #include "core/fxcrt/cfx_bitstream.h" #include "core/fxcrt/fx_safe_types.h" +#include "third_party/base/check.h" #include "third_party/base/numerics/safe_conversions.h" -#include "third_party/base/ptr_util.h" #include "third_party/base/span.h" namespace { @@ -45,8 +46,8 @@ // static std::unique_ptr<CPDF_HintTables> CPDF_HintTables::Parse( CPDF_SyntaxParser* parser, - CPDF_LinearizedHeader* pLinearized) { - ASSERT(parser); + const CPDF_LinearizedHeader* pLinearized) { + DCHECK(parser); if (!pLinearized || pLinearized->GetPageCount() <= 1 || !pLinearized->HasHintTable()) { return nullptr; @@ -67,7 +68,7 @@ if (!hints_stream) return nullptr; - auto pHintTables = pdfium::MakeUnique<CPDF_HintTables>( + auto pHintTables = std::make_unique<CPDF_HintTables>( parser->GetValidator().Get(), pLinearized); if (!pHintTables->LoadHintStream(hints_stream.Get())) return nullptr; @@ -76,15 +77,12 @@ } CPDF_HintTables::CPDF_HintTables(CPDF_ReadValidator* pValidator, - CPDF_LinearizedHeader* pLinearized) - : m_pValidator(pValidator), - m_pLinearized(pLinearized), - m_nFirstPageSharedObjs(0), - m_szFirstPageObjOffset(0) { - ASSERT(m_pLinearized); + const CPDF_LinearizedHeader* pLinearized) + : m_pValidator(pValidator), m_pLinearized(pLinearized) { + DCHECK(m_pLinearized); } -CPDF_HintTables::~CPDF_HintTables() {} +CPDF_HintTables::~CPDF_HintTables() = default; bool CPDF_HintTables::ReadPageHintTable(CFX_BitStream* hStream) { const uint32_t nPages = m_pLinearized->GetPageCount(); @@ -104,7 +102,7 @@ // Item 1: The least number of objects in a page. const uint32_t dwObjLeastNum = hStream->GetBits(32); - if (!dwObjLeastNum) + if (!dwObjLeastNum || dwObjLeastNum >= CPDF_Parser::kMaxObjectNumber) return false; // Item 2: The location of the first page's page object. @@ -167,7 +165,7 @@ m_PageInfos[nFirstPageNum].set_start_obj_num( m_pLinearized->GetFirstPageObjNum()); // The object number of remaining pages starts from 1. - uint32_t dwStartObjNum = 1; + FX_SAFE_UINT32 dwStartObjNum = 1; for (uint32_t i = 0; i < nPages; ++i) { FX_SAFE_UINT32 safeDeltaObj = hStream->GetBits(dwDeltaObjectsBits); safeDeltaObj += dwObjLeastNum; @@ -176,8 +174,12 @@ m_PageInfos[i].set_objects_count(safeDeltaObj.ValueOrDie()); if (i == nFirstPageNum) continue; - m_PageInfos[i].set_start_obj_num(dwStartObjNum); + m_PageInfos[i].set_start_obj_num(dwStartObjNum.ValueOrDie()); dwStartObjNum += m_PageInfos[i].objects_count(); + if (!dwStartObjNum.IsValid() || + dwStartObjNum.ValueOrDie() >= CPDF_Parser::kMaxObjectNumber) { + return false; + } } hStream->ByteAlign(); @@ -194,7 +196,7 @@ m_PageInfos[i].set_page_length(safePageLen.ValueOrDie()); } - ASSERT(m_szFirstPageObjOffset); + DCHECK(m_szFirstPageObjOffset); m_PageInfos[nFirstPageNum].set_page_offset(m_szFirstPageObjOffset); FX_FILESIZE prev_page_end = m_pLinearized->GetFirstPageEndOffset(); for (uint32_t i = 0; i < nPages; ++i) { @@ -407,18 +409,18 @@ CPDF_DataAvail::DocAvailStatus CPDF_HintTables::CheckPage(uint32_t index) { if (index == m_pLinearized->GetFirstPageNo()) - return CPDF_DataAvail::DataAvailable; + return CPDF_DataAvail::kDataAvailable; if (index >= m_pLinearized->GetPageCount()) - return CPDF_DataAvail::DataError; + return CPDF_DataAvail::kDataError; const uint32_t dwLength = m_PageInfos[index].page_length(); if (!dwLength) - return CPDF_DataAvail::DataError; + return CPDF_DataAvail::kDataError; if (!m_pValidator->CheckDataRangeAndRequestIfUnavailable( m_PageInfos[index].page_offset(), dwLength)) { - return CPDF_DataAvail::DataNotAvailable; + return CPDF_DataAvail::kDataNotAvailable; } // Download data of shared objects in the page. @@ -429,22 +431,25 @@ m_SharedObjGroupInfos[dwIndex]; if (!shared_group_info.m_szOffset || !shared_group_info.m_dwLength) - return CPDF_DataAvail::DataError; + return CPDF_DataAvail::kDataError; if (!m_pValidator->CheckDataRangeAndRequestIfUnavailable( shared_group_info.m_szOffset, shared_group_info.m_dwLength)) { - return CPDF_DataAvail::DataNotAvailable; + return CPDF_DataAvail::kDataNotAvailable; } } - return CPDF_DataAvail::DataAvailable; + return CPDF_DataAvail::kDataAvailable; } bool CPDF_HintTables::LoadHintStream(CPDF_Stream* pHintStream) { if (!pHintStream || !m_pLinearized->HasHintTable()) return false; - CPDF_Dictionary* pDict = pHintStream->GetDict(); - CPDF_Object* pOffset = pDict ? pDict->GetObjectFor("S") : nullptr; + RetainPtr<const CPDF_Dictionary> pDict = pHintStream->GetDict(); + if (!pDict) + return false; + + RetainPtr<const CPDF_Object> pOffset = pDict->GetObjectFor("S"); if (!pOffset || !pOffset->IsNumber()) return false; @@ -452,7 +457,8 @@ if (shared_hint_table_offset <= 0) return false; - auto pAcc = pdfium::MakeRetain<CPDF_StreamAcc>(pHintStream); + auto pAcc = + pdfium::MakeRetain<CPDF_StreamAcc>(pdfium::WrapRetain(pHintStream)); pAcc->LoadAllDataFiltered(); uint32_t size = pAcc->GetSize(); @@ -484,7 +490,7 @@ // itself were not present. That is, a position greater than the hint stream // offset shall have the hint stream length added to it to determine the // actual offset relative to the beginning of the file. - // See specification PDF 32000-1:2008 Annex F.4 (Hint tables). + // See ISO 32000-1:2008 spec, annex F.4 (Hint tables). // Note: The PDF spec does not mention this, but positions equal to the hint // stream offset also need to have the hint stream length added to it. e.g. // There exists linearized PDFs generated by Adobe software that have this
diff --git a/core/fpdfapi/parser/cpdf_hint_tables.h b/core/fpdfapi/parser/cpdf_hint_tables.h index e3f280f..072d6e6 100644 --- a/core/fpdfapi/parser/cpdf_hint_tables.h +++ b/core/fpdfapi/parser/cpdf_hint_tables.h
@@ -1,4 +1,4 @@ -// Copyright 2016 PDFium Authors. All rights reserved. +// Copyright 2016 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -70,10 +70,10 @@ static std::unique_ptr<CPDF_HintTables> Parse( CPDF_SyntaxParser* parser, - CPDF_LinearizedHeader* pLinearized); + const CPDF_LinearizedHeader* pLinearized); CPDF_HintTables(CPDF_ReadValidator* pValidator, - CPDF_LinearizedHeader* pLinearized); + const CPDF_LinearizedHeader* pLinearized); virtual ~CPDF_HintTables(); bool GetPagePos(uint32_t index, @@ -99,17 +99,12 @@ private: FX_FILESIZE HintsOffsetToFileOffset(uint32_t hints_offset) const; - // Owned by |m_pDataAvail|. - UnownedPtr<CPDF_ReadValidator> m_pValidator; - - // Owned by |m_pDataAvail|. - UnownedPtr<CPDF_LinearizedHeader> const m_pLinearized; - - uint32_t m_nFirstPageSharedObjs; - FX_FILESIZE m_szFirstPageObjOffset; - + uint32_t m_nFirstPageSharedObjs = 0; + FX_FILESIZE m_szFirstPageObjOffset = 0; std::vector<PageInfo> m_PageInfos; std::vector<SharedObjGroupInfo> m_SharedObjGroupInfos; + UnownedPtr<CPDF_ReadValidator> m_pValidator; + UnownedPtr<const CPDF_LinearizedHeader> const m_pLinearized; }; #endif // CORE_FPDFAPI_PARSER_CPDF_HINT_TABLES_H_
diff --git a/core/fpdfapi/parser/cpdf_hint_tables_unittest.cpp b/core/fpdfapi/parser/cpdf_hint_tables_unittest.cpp index 27592ba..c61afa1 100644 --- a/core/fpdfapi/parser/cpdf_hint_tables_unittest.cpp +++ b/core/fpdfapi/parser/cpdf_hint_tables_unittest.cpp
@@ -1,4 +1,4 @@ -// Copyright 2017 PDFium Authors. All rights reserved. +// Copyright 2017 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -8,7 +8,7 @@ #include <string> #include <utility> -#include "core/fpdfapi/page/cpdf_pagemodule.h" +#include "core/fpdfapi/page/test_with_page_module.h" #include "core/fpdfapi/parser/cpdf_data_avail.h" #include "core/fpdfapi/parser/cpdf_dictionary.h" #include "core/fpdfapi/parser/cpdf_linearized_header.h" @@ -16,12 +16,13 @@ #include "core/fpdfapi/parser/cpdf_read_validator.h" #include "core/fpdfapi/parser/cpdf_stream.h" #include "core/fpdfapi/parser/cpdf_syntax_parser.h" -#include "core/fxcrt/cfx_readonlymemorystream.h" +#include "core/fxcrt/bytestring.h" +#include "core/fxcrt/cfx_read_only_string_stream.h" #include "core/fxcrt/fx_stream.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" #include "testing/utils/path_service.h" -#include "third_party/base/ptr_util.h" +#include "third_party/base/check.h" namespace { @@ -29,15 +30,15 @@ const std::string& file_name) { std::string file_path; PathService::GetTestFilePath(file_name, &file_path); - ASSERT(!file_path.empty()); + DCHECK(!file_path.empty()); return pdfium::MakeRetain<CPDF_ReadValidator>( IFX_SeekableReadStream::CreateFromFilename(file_path.c_str()), nullptr); } std::unique_ptr<CPDF_DataAvail> MakeDataAvailFromFile( const std::string& file_name) { - return pdfium::MakeUnique<CPDF_DataAvail>( - nullptr, MakeValidatorFromFile(file_name), true); + return std::make_unique<CPDF_DataAvail>(nullptr, + MakeValidatorFromFile(file_name)); } class TestLinearizedHeader final : public CPDF_LinearizedHeader { @@ -47,36 +48,28 @@ : CPDF_LinearizedHeader(pDict, szLastXRefOffset) {} static std::unique_ptr<CPDF_LinearizedHeader> MakeHeader( - const std::string& inline_data) { - CPDF_SyntaxParser parser(pdfium::MakeRetain<CFX_ReadOnlyMemoryStream>( - pdfium::as_bytes(pdfium::make_span(inline_data)))); + ByteString inline_data) { + CPDF_SyntaxParser parser( + pdfium::MakeRetain<CFX_ReadOnlyStringStream>(std::move(inline_data))); RetainPtr<CPDF_Dictionary> dict = ToDictionary(parser.GetObjectBody(nullptr)); - ASSERT(dict); - return pdfium::MakeUnique<TestLinearizedHeader>(dict.Get(), 0); + DCHECK(dict); + return std::make_unique<TestLinearizedHeader>(dict.Get(), 0); } }; } // namespace -class CPDF_HintTablesTest : public testing::Test { - public: - CPDF_HintTablesTest() { - // Needs for encoding Hint table stream. - CPDF_PageModule::Create(); - } +// Needs page module for encoding Hint table stream. +using HintTablesTest = TestWithPageModule; - ~CPDF_HintTablesTest() override { CPDF_PageModule::Destroy(); } -}; - -TEST_F(CPDF_HintTablesTest, Load) { +TEST_F(HintTablesTest, Load) { auto data_avail = MakeDataAvailFromFile("feature_linearized_loading.pdf"); - ASSERT_EQ(CPDF_DataAvail::DocAvailStatus::DataAvailable, - data_avail->IsDocAvail(nullptr)); + ASSERT_EQ(CPDF_DataAvail::kDataAvailable, data_avail->IsDocAvail(nullptr)); - ASSERT_TRUE(data_avail->GetHintTables()); + ASSERT_TRUE(data_avail->GetHintTablesForTest()); - const CPDF_HintTables* hint_tables = data_avail->GetHintTables(); + const CPDF_HintTables* hint_tables = data_avail->GetHintTablesForTest(); FX_FILESIZE page_start = 0; FX_FILESIZE page_length = 0; uint32_t page_obj_num = 0; @@ -97,12 +90,11 @@ hint_tables->GetPagePos(2, &page_start, &page_length, &page_obj_num)); } -TEST_F(CPDF_HintTablesTest, PageAndGroupInfos) { +TEST_F(HintTablesTest, PageAndGroupInfos) { auto data_avail = MakeDataAvailFromFile("feature_linearized_loading.pdf"); - ASSERT_EQ(CPDF_DataAvail::DocAvailStatus::DataAvailable, - data_avail->IsDocAvail(nullptr)); + ASSERT_EQ(CPDF_DataAvail::kDataAvailable, data_avail->IsDocAvail(nullptr)); - const CPDF_HintTables* hint_tables = data_avail->GetHintTables(); + const CPDF_HintTables* hint_tables = data_avail->GetHintTablesForTest(); ASSERT_TRUE(hint_tables); ASSERT_EQ(2u, hint_tables->PageInfos().size()); @@ -159,7 +151,7 @@ EXPECT_EQ(1u, hint_tables->SharedGroupInfos()[5].m_dwObjectsCount); } -TEST_F(CPDF_HintTablesTest, FirstPageOffset) { +TEST_F(HintTablesTest, FirstPageOffset) { // Test that valid hint table is loaded, and have correct offset of first page // object. const auto linearized_header = TestLinearizedHeader::MakeHeader( @@ -172,8 +164,8 @@ CPDF_SyntaxParser parser(validator, 0); RetainPtr<CPDF_Stream> stream = ToStream(parser.GetObjectBody(nullptr)); ASSERT_TRUE(stream); - auto hint_tables = pdfium::MakeUnique<CPDF_HintTables>( - validator.Get(), linearized_header.get()); + auto hint_tables = std::make_unique<CPDF_HintTables>(validator.Get(), + linearized_header.get()); // Check that hint table will load. ASSERT_TRUE(hint_tables->LoadHintStream(stream.Get())); // Check that hint table have correct first page offset.
diff --git a/core/fpdfapi/parser/cpdf_indirect_object_holder.cpp b/core/fpdfapi/parser/cpdf_indirect_object_holder.cpp index b2e1b54..d4ff401 100644 --- a/core/fpdfapi/parser/cpdf_indirect_object_holder.cpp +++ b/core/fpdfapi/parser/cpdf_indirect_object_holder.cpp
@@ -1,4 +1,4 @@ -// Copyright 2016 PDFium Authors. All rights reserved. +// Copyright 2016 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -7,46 +7,64 @@ #include "core/fpdfapi/parser/cpdf_indirect_object_holder.h" #include <algorithm> +#include <memory> #include <utility> #include "core/fpdfapi/parser/cpdf_object.h" #include "core/fpdfapi/parser/cpdf_parser.h" -#include "third_party/base/logging.h" -#include "third_party/base/ptr_util.h" +#include "third_party/base/check.h" namespace { -CPDF_Object* FilterInvalidObjNum(CPDF_Object* obj) { +const CPDF_Object* FilterInvalidObjNum(const CPDF_Object* obj) { return obj && obj->GetObjNum() != CPDF_Object::kInvalidObjNum ? obj : nullptr; } } // namespace CPDF_IndirectObjectHolder::CPDF_IndirectObjectHolder() - : m_LastObjNum(0), - m_pByteStringPool(pdfium::MakeUnique<ByteStringPool>()) {} + : m_pByteStringPool(std::make_unique<ByteStringPool>()) {} CPDF_IndirectObjectHolder::~CPDF_IndirectObjectHolder() { m_pByteStringPool.DeleteObject(); // Make weak. } -CPDF_Object* CPDF_IndirectObjectHolder::GetIndirectObject( +RetainPtr<const CPDF_Object> CPDF_IndirectObjectHolder::GetIndirectObject( uint32_t objnum) const { - auto it = m_IndirectObjs.find(objnum); - return (it != m_IndirectObjs.end()) ? FilterInvalidObjNum(it->second.Get()) - : nullptr; + return pdfium::WrapRetain(GetIndirectObjectInternal(objnum)); } -CPDF_Object* CPDF_IndirectObjectHolder::GetOrParseIndirectObject( +RetainPtr<CPDF_Object> CPDF_IndirectObjectHolder::GetMutableIndirectObject( + uint32_t objnum) { + return pdfium::WrapRetain( + const_cast<CPDF_Object*>(GetIndirectObjectInternal(objnum))); +} + +const CPDF_Object* CPDF_IndirectObjectHolder::GetIndirectObjectInternal( + uint32_t objnum) const { + auto it = m_IndirectObjs.find(objnum); + if (it == m_IndirectObjs.end()) + return nullptr; + + return FilterInvalidObjNum(it->second.Get()); +} + +RetainPtr<CPDF_Object> CPDF_IndirectObjectHolder::GetOrParseIndirectObject( + uint32_t objnum) { + return pdfium::WrapRetain(GetOrParseIndirectObjectInternal(objnum)); +} + +CPDF_Object* CPDF_IndirectObjectHolder::GetOrParseIndirectObjectInternal( uint32_t objnum) { if (objnum == 0 || objnum == CPDF_Object::kInvalidObjNum) return nullptr; // Add item anyway to prevent recursively parsing of same object. auto insert_result = m_IndirectObjs.insert(std::make_pair(objnum, nullptr)); - if (!insert_result.second) - return FilterInvalidObjNum(insert_result.first->second.Get()); - + if (!insert_result.second) { + return const_cast<CPDF_Object*>( + FilterInvalidObjNum(insert_result.first->second.Get())); + } RetainPtr<CPDF_Object> pNewObj = ParseIndirectObject(objnum); if (!pNewObj) { m_IndirectObjs.erase(insert_result.first); @@ -55,8 +73,10 @@ pNewObj->SetObjNum(objnum); m_LastObjNum = std::max(m_LastObjNum, objnum); + + CPDF_Object* result = pNewObj.Get(); insert_result.first->second = std::move(pNewObj); - return insert_result.first->second.Get(); + return result; } RetainPtr<CPDF_Object> CPDF_IndirectObjectHolder::ParseIndirectObject( @@ -64,20 +84,18 @@ return nullptr; } -CPDF_Object* CPDF_IndirectObjectHolder::AddIndirectObject( +uint32_t CPDF_IndirectObjectHolder::AddIndirectObject( RetainPtr<CPDF_Object> pObj) { CHECK(!pObj->GetObjNum()); pObj->SetObjNum(++m_LastObjNum); - - auto& obj_holder = m_IndirectObjs[m_LastObjNum]; - obj_holder = std::move(pObj); - return obj_holder.Get(); + m_IndirectObjs[m_LastObjNum] = std::move(pObj); + return m_LastObjNum; } bool CPDF_IndirectObjectHolder::ReplaceIndirectObjectIfHigherGeneration( uint32_t objnum, RetainPtr<CPDF_Object> pObj) { - ASSERT(objnum); + DCHECK(objnum); if (!pObj || objnum == CPDF_Object::kInvalidObjNum) return false;
diff --git a/core/fpdfapi/parser/cpdf_indirect_object_holder.h b/core/fpdfapi/parser/cpdf_indirect_object_holder.h index 1887cc8..cdf0bc8 100644 --- a/core/fpdfapi/parser/cpdf_indirect_object_holder.h +++ b/core/fpdfapi/parser/cpdf_indirect_object_holder.h
@@ -1,4 +1,4 @@ -// Copyright 2016 PDFium Authors. All rights reserved. +// Copyright 2016 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -7,17 +7,16 @@ #ifndef CORE_FPDFAPI_PARSER_CPDF_INDIRECT_OBJECT_HOLDER_H_ #define CORE_FPDFAPI_PARSER_CPDF_INDIRECT_OBJECT_HOLDER_H_ +#include <stdint.h> + #include <map> -#include <memory> #include <type_traits> #include <utility> -#include <vector> #include "core/fpdfapi/parser/cpdf_object.h" -#include "core/fxcrt/fx_system.h" +#include "core/fxcrt/retain_ptr.h" #include "core/fxcrt/string_pool_template.h" #include "core/fxcrt/weak_ptr.h" -#include "third_party/base/ptr_util.h" class CPDF_IndirectObjectHolder { public: @@ -27,39 +26,39 @@ CPDF_IndirectObjectHolder(); virtual ~CPDF_IndirectObjectHolder(); - CPDF_Object* GetIndirectObject(uint32_t objnum) const; - virtual CPDF_Object* GetOrParseIndirectObject(uint32_t objnum); + RetainPtr<CPDF_Object> GetOrParseIndirectObject(uint32_t objnum); + RetainPtr<const CPDF_Object> GetIndirectObject(uint32_t objnum) const; + RetainPtr<CPDF_Object> GetMutableIndirectObject(uint32_t objnum); void DeleteIndirectObject(uint32_t objnum); - // Creates and adds a new object owned by the indirect object holder, - // and returns an unowned pointer to it. We have a special case to - // handle objects that can intern strings from our ByteStringPool. + // Creates and adds a new object retained by the indirect object holder, + // and returns a retained pointer to it. template <typename T, typename... Args> - typename std::enable_if<!CanInternStrings<T>::value, T*>::type NewIndirect( - Args&&... args) { - return static_cast<T*>( - AddIndirectObject(pdfium::MakeRetain<T>(std::forward<Args>(args)...))); - } - template <typename T, typename... Args> - typename std::enable_if<CanInternStrings<T>::value, T*>::type NewIndirect( - Args&&... args) { - return static_cast<T*>(AddIndirectObject( - pdfium::MakeRetain<T>(m_pByteStringPool, std::forward<Args>(args)...))); + RetainPtr<T> NewIndirect(Args&&... args) { + auto obj = New<T>(std::forward<Args>(args)...); + AddIndirectObject(obj); + return obj; } - // Creates and adds a new object not owned by the indirect object holder, - // but which can intern strings from it. + // Creates and adds a new object not retained by the indirect object holder, + // but which can intern strings from it. We have a special cast to handle + // objects that can intern strings from our ByteStringPool. template <typename T, typename... Args> typename std::enable_if<CanInternStrings<T>::value, RetainPtr<T>>::type New( Args&&... args) { return pdfium::MakeRetain<T>(m_pByteStringPool, std::forward<Args>(args)...); } + template <typename T, typename... Args> + typename std::enable_if<!CanInternStrings<T>::value, RetainPtr<T>>::type New( + Args&&... args) { + return pdfium::MakeRetain<T>(std::forward<Args>(args)...); + } - // Takes ownership of |pObj|, returns unowned pointer to it. - CPDF_Object* AddIndirectObject(RetainPtr<CPDF_Object> pObj); + // Always Retains |pObj|, returns its new object number. + uint32_t AddIndirectObject(RetainPtr<CPDF_Object> pObj); - // Always takes ownership of |pObj|, return true if higher generation number. + // If higher generation number, retains |pObj| and returns true. bool ReplaceIndirectObjectIfHigherGeneration(uint32_t objnum, RetainPtr<CPDF_Object> pObj); @@ -77,7 +76,12 @@ virtual RetainPtr<CPDF_Object> ParseIndirectObject(uint32_t objnum); private: - uint32_t m_LastObjNum; + friend class CPDF_Reference; + + const CPDF_Object* GetIndirectObjectInternal(uint32_t objnum) const; + CPDF_Object* GetOrParseIndirectObjectInternal(uint32_t objnum); + + uint32_t m_LastObjNum = 0; std::map<uint32_t, RetainPtr<CPDF_Object>> m_IndirectObjs; WeakPtr<ByteStringPool> m_pByteStringPool; };
diff --git a/core/fpdfapi/parser/cpdf_indirect_object_holder_unittest.cpp b/core/fpdfapi/parser/cpdf_indirect_object_holder_unittest.cpp index 5494855..94e9b38 100644 --- a/core/fpdfapi/parser/cpdf_indirect_object_holder_unittest.cpp +++ b/core/fpdfapi/parser/cpdf_indirect_object_holder_unittest.cpp
@@ -1,37 +1,36 @@ -// Copyright 2017 PDFium Authors. All rights reserved. +// Copyright 2017 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "core/fpdfapi/parser/cpdf_indirect_object_holder.h" -#include <memory> -#include <utility> - +#include "core/fpdfapi/parser/cpdf_array.h" +#include "core/fpdfapi/parser/cpdf_dictionary.h" #include "core/fpdfapi/parser/cpdf_null.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" -#include "third_party/base/ptr_util.h" +#include "third_party/base/check.h" namespace { class MockIndirectObjectHolder final : public CPDF_IndirectObjectHolder { public: - MockIndirectObjectHolder() {} - ~MockIndirectObjectHolder() override {} + MockIndirectObjectHolder() = default; + ~MockIndirectObjectHolder() override = default; MOCK_METHOD1(ParseIndirectObject, RetainPtr<CPDF_Object>(uint32_t objnum)); }; } // namespace -TEST(CPDF_IndirectObjectHolderTest, RecursiveParseOfSameObject) { +TEST(IndirectObjectHolderTest, RecursiveParseOfSameObject) { MockIndirectObjectHolder mock_holder; // ParseIndirectObject should not be called again on recursively same object // parse request. EXPECT_CALL(mock_holder, ParseIndirectObject(::testing::_)) .WillOnce(::testing::WithArg<0>(::testing::Invoke( [&mock_holder](uint32_t objnum) -> RetainPtr<CPDF_Object> { - const CPDF_Object* same_parse = + RetainPtr<const CPDF_Object> same_parse = mock_holder.GetOrParseIndirectObject(objnum); CHECK(!same_parse); return pdfium::MakeRetain<CPDF_Null>(); @@ -40,7 +39,7 @@ EXPECT_TRUE(mock_holder.GetOrParseIndirectObject(1000)); } -TEST(CPDF_IndirectObjectHolderTest, GetObjectMethods) { +TEST(IndirectObjectHolderTest, GetObjectMethods) { static constexpr uint32_t kObjNum = 1000; MockIndirectObjectHolder mock_holder; @@ -63,7 +62,7 @@ EXPECT_EQ(kObjNum, mock_holder.GetIndirectObject(kObjNum)->GetObjNum()); } -TEST(CPDF_IndirectObjectHolderTest, ParseInvalidObjNum) { +TEST(IndirectObjectHolderTest, ParseInvalidObjNum) { MockIndirectObjectHolder mock_holder; EXPECT_CALL(mock_holder, ParseIndirectObject(::testing::_)).Times(0); @@ -71,10 +70,23 @@ mock_holder.GetOrParseIndirectObject(CPDF_Object::kInvalidObjNum)); } -TEST(CPDF_IndirectObjectHolderTest, ReplaceObjectWithInvalidObjNum) { +TEST(IndirectObjectHolderTest, ReplaceObjectWithInvalidObjNum) { MockIndirectObjectHolder mock_holder; EXPECT_CALL(mock_holder, ParseIndirectObject(::testing::_)).Times(0); EXPECT_FALSE(mock_holder.ReplaceIndirectObjectIfHigherGeneration( CPDF_Object::kInvalidObjNum, pdfium::MakeRetain<CPDF_Null>())); } + +TEST(IndirectObjectHolderTest, TemplateNewMethods) { + MockIndirectObjectHolder mock_holder; + + auto pDict = mock_holder.NewIndirect<CPDF_Dictionary>(); + auto pArray = mock_holder.NewIndirect<CPDF_Array>(); + mock_holder.DeleteIndirectObject(pDict->GetObjNum()); + mock_holder.DeleteIndirectObject(pArray->GetObjNum()); + + // No longer UAF since NewIndirect<> returns retained objects. + EXPECT_TRUE(pDict->IsDictionary()); + EXPECT_TRUE(pArray->IsArray()); +}
diff --git a/core/fpdfapi/parser/cpdf_linearized_header.cpp b/core/fpdfapi/parser/cpdf_linearized_header.cpp index c7dc54a..f4de7d7 100644 --- a/core/fpdfapi/parser/cpdf_linearized_header.cpp +++ b/core/fpdfapi/parser/cpdf_linearized_header.cpp
@@ -1,4 +1,4 @@ -// Copyright 2016 PDFium Authors. All rights reserved. +// Copyright 2016 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -13,8 +13,10 @@ #include "core/fpdfapi/parser/cpdf_array.h" #include "core/fpdfapi/parser/cpdf_dictionary.h" #include "core/fpdfapi/parser/cpdf_number.h" +#include "core/fpdfapi/parser/cpdf_parser.h" #include "core/fpdfapi/parser/cpdf_syntax_parser.h" #include "core/fxcrt/fx_safe_types.h" +#include "third_party/base/check.h" #include "third_party/base/ptr_util.h" namespace { @@ -24,12 +26,12 @@ template <class T> bool IsValidNumericDictionaryValue(const CPDF_Dictionary* pDict, - const char* key, + const ByteString& key, T min_value, bool must_exist = true) { if (!pDict->KeyExist(key)) return !must_exist; - const CPDF_Number* pNum = ToNumber(pDict->GetObjectFor(key)); + RetainPtr<const CPDF_Number> pNum = pDict->GetNumberFor(key); if (!pNum || !pNum->IsInteger()) return false; const int raw_value = pNum->GetInteger(); @@ -40,12 +42,13 @@ bool IsLinearizedHeaderValid(const CPDF_LinearizedHeader* header, FX_FILESIZE document_size) { - ASSERT(header); + DCHECK(header); return header->GetFileSize() == document_size && header->GetFirstPageNo() < kMaxInt && header->GetFirstPageNo() < header->GetPageCount() && header->GetMainXRefTableFirstEntryOffset() < document_size && header->GetFirstPageEndOffset() < document_size && + header->GetFirstPageObjNum() < CPDF_Parser::kMaxObjectNumber && header->GetLastXRefOffset() < document_size && header->GetHintStart() < document_size; } @@ -71,7 +74,7 @@ } // Move parser to the start of the xref table for the documents first page. // (skpping endobj keyword) - if (parser->GetNextWord(nullptr) != "endobj") + if (parser->GetNextWord().word != "endobj") return nullptr; auto result = pdfium::WrapUnique( @@ -92,7 +95,7 @@ m_szFirstPageEndOffset(pDict->GetIntegerFor("E")), m_FirstPageObjNum(pDict->GetIntegerFor("O")), m_szLastXRefOffset(szLastXRefOffset) { - const CPDF_Array* pHintStreamRange = pDict->GetArrayFor("H"); + RetainPtr<const CPDF_Array> pHintStreamRange = pDict->GetArrayFor("H"); const size_t nHintStreamSize = pHintStreamRange ? pHintStreamRange->size() : 0; if (nHintStreamSize == 2 || nHintStreamSize == 4) { @@ -103,7 +106,7 @@ } } -CPDF_LinearizedHeader::~CPDF_LinearizedHeader() {} +CPDF_LinearizedHeader::~CPDF_LinearizedHeader() = default; bool CPDF_LinearizedHeader::HasHintTable() const { return GetPageCount() > 1 && GetHintStart() > 0 && GetHintLength() > 0;
diff --git a/core/fpdfapi/parser/cpdf_linearized_header.h b/core/fpdfapi/parser/cpdf_linearized_header.h index 44e0422..10e2453 100644 --- a/core/fpdfapi/parser/cpdf_linearized_header.h +++ b/core/fpdfapi/parser/cpdf_linearized_header.h
@@ -1,4 +1,4 @@ -// Copyright 2016 PDFium Authors. All rights reserved. +// Copyright 2016 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -7,12 +7,13 @@ #ifndef CORE_FPDFAPI_PARSER_CPDF_LINEARIZED_HEADER_H_ #define CORE_FPDFAPI_PARSER_CPDF_LINEARIZED_HEADER_H_ +#include <stdint.h> + #include <memory> -#include "core/fxcrt/fx_system.h" +#include "core/fxcrt/fx_types.h" class CPDF_Dictionary; -class CPDF_Object; class CPDF_SyntaxParser; class CPDF_LinearizedHeader { @@ -31,7 +32,7 @@ uint32_t GetPageCount() const { return m_PageCount; } // Will only return values > 0. FX_FILESIZE GetFirstPageEndOffset() const { return m_szFirstPageEndOffset; } - // Will only return values > 0. + // Will only return values in the range [1, `CPDF_Parser::kMaxObjectNumber`). uint32_t GetFirstPageObjNum() const { return m_FirstPageObjNum; } // Will only return values > 0. FX_FILESIZE GetLastXRefOffset() const { return m_szLastXRefOffset; }
diff --git a/core/fpdfapi/parser/cpdf_name.cpp b/core/fpdfapi/parser/cpdf_name.cpp index 9f3f49f..6236ef4 100644 --- a/core/fpdfapi/parser/cpdf_name.cpp +++ b/core/fpdfapi/parser/cpdf_name.cpp
@@ -1,4 +1,4 @@ -// Copyright 2016 PDFium Authors. All rights reserved. +// Copyright 2016 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -9,7 +9,6 @@ #include "core/fpdfapi/parser/fpdf_parser_decode.h" #include "core/fpdfapi/parser/fpdf_parser_utility.h" #include "core/fxcrt/fx_stream.h" -#include "third_party/base/ptr_util.h" CPDF_Name::CPDF_Name(WeakPtr<ByteStringPool> pPool, const ByteString& str) : m_Name(str) { @@ -17,7 +16,7 @@ m_Name = pPool->Intern(m_Name); } -CPDF_Name::~CPDF_Name() {} +CPDF_Name::~CPDF_Name() = default; CPDF_Object::Type CPDF_Name::GetType() const { return kName; @@ -35,15 +34,7 @@ m_Name = str; } -bool CPDF_Name::IsName() const { - return true; -} - -CPDF_Name* CPDF_Name::AsName() { - return this; -} - -const CPDF_Name* CPDF_Name::AsName() const { +CPDF_Name* CPDF_Name::AsMutableName() { return this; } @@ -53,6 +44,9 @@ bool CPDF_Name::WriteTo(IFX_ArchiveStream* archive, const CPDF_Encryptor* encryptor) const { - return archive->WriteString("/") && - archive->WriteString(PDF_NameEncode(GetString()).AsStringView()); + if (!archive->WriteString("/")) + return false; + + const ByteString name = PDF_NameEncode(GetString()); + return name.IsEmpty() || archive->WriteString(name.AsStringView()); }
diff --git a/core/fpdfapi/parser/cpdf_name.h b/core/fpdfapi/parser/cpdf_name.h index cfd90bb..c3c023f 100644 --- a/core/fpdfapi/parser/cpdf_name.h +++ b/core/fpdfapi/parser/cpdf_name.h
@@ -1,4 +1,4 @@ -// Copyright 2016 PDFium Authors. All rights reserved. +// Copyright 2016 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -7,16 +7,14 @@ #ifndef CORE_FPDFAPI_PARSER_CPDF_NAME_H_ #define CORE_FPDFAPI_PARSER_CPDF_NAME_H_ -#include <memory> - #include "core/fpdfapi/parser/cpdf_object.h" +#include "core/fxcrt/retain_ptr.h" #include "core/fxcrt/string_pool_template.h" #include "core/fxcrt/weak_ptr.h" class CPDF_Name final : public CPDF_Object { public: - template <typename T, typename... Args> - friend RetainPtr<T> pdfium::MakeRetain(Args&&... args); + CONSTRUCT_VIA_MAKE_RETAIN; // CPDF_Object: Type GetType() const override; @@ -24,9 +22,7 @@ ByteString GetString() const override; WideString GetUnicodeText() const override; void SetString(const ByteString& str) override; - bool IsName() const override; - CPDF_Name* AsName() override; - const CPDF_Name* AsName() const override; + CPDF_Name* AsMutableName() override; bool WriteTo(IFX_ArchiveStream* archive, const CPDF_Encryptor* encryptor) const override; @@ -38,11 +34,19 @@ }; inline CPDF_Name* ToName(CPDF_Object* obj) { - return obj ? obj->AsName() : nullptr; + return obj ? obj->AsMutableName() : nullptr; } inline const CPDF_Name* ToName(const CPDF_Object* obj) { return obj ? obj->AsName() : nullptr; } +inline RetainPtr<const CPDF_Name> ToName(RetainPtr<CPDF_Object> obj) { + return RetainPtr<CPDF_Name>(ToName(obj.Get())); +} + +inline RetainPtr<const CPDF_Name> ToName(RetainPtr<const CPDF_Object> obj) { + return RetainPtr<const CPDF_Name>(ToName(obj.Get())); +} + #endif // CORE_FPDFAPI_PARSER_CPDF_NAME_H_
diff --git a/core/fpdfapi/parser/cpdf_null.cpp b/core/fpdfapi/parser/cpdf_null.cpp index 71299c1..44a6c45 100644 --- a/core/fpdfapi/parser/cpdf_null.cpp +++ b/core/fpdfapi/parser/cpdf_null.cpp
@@ -1,4 +1,4 @@ -// Copyright 2016 PDFium Authors. All rights reserved. +// Copyright 2016 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -7,9 +7,8 @@ #include "core/fpdfapi/parser/cpdf_null.h" #include "core/fxcrt/fx_stream.h" -#include "third_party/base/ptr_util.h" -CPDF_Null::CPDF_Null() {} +CPDF_Null::CPDF_Null() = default; CPDF_Object::Type CPDF_Null::GetType() const { return kNullobj; @@ -19,11 +18,11 @@ return pdfium::MakeRetain<CPDF_Null>(); } +CPDF_Null* CPDF_Null::AsMutableNull() { + return this; +} + bool CPDF_Null::WriteTo(IFX_ArchiveStream* archive, const CPDF_Encryptor* encryptor) const { return archive->WriteString(" null"); } - -bool CPDF_Null::IsNull() const { - return true; -}
diff --git a/core/fpdfapi/parser/cpdf_null.h b/core/fpdfapi/parser/cpdf_null.h index 767583b..3d5a237 100644 --- a/core/fpdfapi/parser/cpdf_null.h +++ b/core/fpdfapi/parser/cpdf_null.h
@@ -1,4 +1,4 @@ -// Copyright 2016 PDFium Authors. All rights reserved. +// Copyright 2016 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -7,21 +7,19 @@ #ifndef CORE_FPDFAPI_PARSER_CPDF_NULL_H_ #define CORE_FPDFAPI_PARSER_CPDF_NULL_H_ -#include <memory> - #include "core/fpdfapi/parser/cpdf_object.h" +#include "core/fxcrt/retain_ptr.h" class CPDF_Null final : public CPDF_Object { public: - template <typename T, typename... Args> - friend RetainPtr<T> pdfium::MakeRetain(Args&&... args); + CONSTRUCT_VIA_MAKE_RETAIN; // CPDF_Object. Type GetType() const override; RetainPtr<CPDF_Object> Clone() const override; + CPDF_Null* AsMutableNull() override; bool WriteTo(IFX_ArchiveStream* archive, const CPDF_Encryptor* encryptor) const override; - bool IsNull() const override; private: CPDF_Null();
diff --git a/core/fpdfapi/parser/cpdf_number.cpp b/core/fpdfapi/parser/cpdf_number.cpp index 24abf20..6b9d78d 100644 --- a/core/fpdfapi/parser/cpdf_number.cpp +++ b/core/fpdfapi/parser/cpdf_number.cpp
@@ -1,4 +1,4 @@ -// Copyright 2016 PDFium Authors. All rights reserved. +// Copyright 2016 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -7,9 +7,8 @@ #include "core/fpdfapi/parser/cpdf_number.h" #include "core/fxcrt/fx_stream.h" -#include "third_party/base/ptr_util.h" -CPDF_Number::CPDF_Number() {} +CPDF_Number::CPDF_Number() = default; CPDF_Number::CPDF_Number(int value) : m_Number(value) {} @@ -17,7 +16,7 @@ CPDF_Number::CPDF_Number(ByteStringView str) : m_Number(str) {} -CPDF_Number::~CPDF_Number() {} +CPDF_Number::~CPDF_Number() = default; CPDF_Object::Type CPDF_Number::GetType() const { return kNumber; @@ -37,15 +36,7 @@ return m_Number.GetSigned(); } -bool CPDF_Number::IsNumber() const { - return true; -} - -CPDF_Number* CPDF_Number::AsNumber() { - return this; -} - -const CPDF_Number* CPDF_Number::AsNumber() const { +CPDF_Number* CPDF_Number::AsMutableNumber() { return this; }
diff --git a/core/fpdfapi/parser/cpdf_number.h b/core/fpdfapi/parser/cpdf_number.h index dc75340..93b0f9d 100644 --- a/core/fpdfapi/parser/cpdf_number.h +++ b/core/fpdfapi/parser/cpdf_number.h
@@ -1,4 +1,4 @@ -// Copyright 2016 PDFium Authors. All rights reserved. +// Copyright 2016 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -7,17 +7,14 @@ #ifndef CORE_FPDFAPI_PARSER_CPDF_NUMBER_H_ #define CORE_FPDFAPI_PARSER_CPDF_NUMBER_H_ -#include <memory> - #include "core/fpdfapi/parser/cpdf_object.h" +#include "core/fxcrt/bytestring.h" #include "core/fxcrt/fx_number.h" -#include "core/fxcrt/fx_string.h" -#include "core/fxcrt/fx_system.h" +#include "core/fxcrt/retain_ptr.h" class CPDF_Number final : public CPDF_Object { public: - template <typename T, typename... Args> - friend RetainPtr<T> pdfium::MakeRetain(Args&&... args); + CONSTRUCT_VIA_MAKE_RETAIN; // CPDF_Object: Type GetType() const override; @@ -26,9 +23,7 @@ float GetNumber() const override; int GetInteger() const override; void SetString(const ByteString& str) override; - bool IsNumber() const override; - CPDF_Number* AsNumber() override; - const CPDF_Number* AsNumber() const override; + CPDF_Number* AsMutableNumber() override; bool WriteTo(IFX_ArchiveStream* archive, const CPDF_Encryptor* encryptor) const override; @@ -45,11 +40,19 @@ }; inline CPDF_Number* ToNumber(CPDF_Object* obj) { - return obj ? obj->AsNumber() : nullptr; + return obj ? obj->AsMutableNumber() : nullptr; } inline const CPDF_Number* ToNumber(const CPDF_Object* obj) { return obj ? obj->AsNumber() : nullptr; } +inline RetainPtr<CPDF_Number> ToNumber(RetainPtr<CPDF_Object> obj) { + return RetainPtr<CPDF_Number>(ToNumber(obj.Get())); +} + +inline RetainPtr<const CPDF_Number> ToNumber(RetainPtr<const CPDF_Object> obj) { + return RetainPtr<const CPDF_Number>(ToNumber(obj.Get())); +} + #endif // CORE_FPDFAPI_PARSER_CPDF_NUMBER_H_
diff --git a/core/fpdfapi/parser/cpdf_object.cpp b/core/fpdfapi/parser/cpdf_object.cpp index b61ee7e..3916392 100644 --- a/core/fpdfapi/parser/cpdf_object.cpp +++ b/core/fpdfapi/parser/cpdf_object.cpp
@@ -1,4 +1,4 @@ -// Copyright 2016 PDFium Authors. All rights reserved. +// Copyright 2016 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -14,16 +14,33 @@ #include "core/fpdfapi/parser/cpdf_parser.h" #include "core/fpdfapi/parser/cpdf_reference.h" #include "core/fxcrt/fx_string.h" -#include "third_party/base/logging.h" -#include "third_party/base/ptr_util.h" +#include "third_party/base/notreached.h" -CPDF_Object::~CPDF_Object() {} +CPDF_Object::~CPDF_Object() = default; -CPDF_Object* CPDF_Object::GetDirect() { - return this; +static_assert(sizeof(uint64_t) >= sizeof(CPDF_Object*), + "Need a bigger type for cache keys"); + +static_assert(CPDF_Parser::kMaxObjectNumber < static_cast<uint32_t>(1) << 31, + "Need a smaller kMaxObjNumber for cache keys"); + +uint64_t CPDF_Object::KeyForCache() const { + if (IsInline()) + return (static_cast<uint64_t>(1) << 63) | reinterpret_cast<uint64_t>(this); + + return (static_cast<uint64_t>(m_ObjNum) << 32) | + static_cast<uint64_t>(m_GenNum); } -const CPDF_Object* CPDF_Object::GetDirect() const { +RetainPtr<CPDF_Object> CPDF_Object::GetMutableDirect() { + return pdfium::WrapRetain(const_cast<CPDF_Object*>(GetDirectInternal())); +} + +RetainPtr<const CPDF_Object> CPDF_Object::GetDirect() const { + return pdfium::WrapRetain(GetDirectInternal()); +} + +const CPDF_Object* CPDF_Object::GetDirectInternal() const { return this; } @@ -58,11 +75,15 @@ return 0; } -CPDF_Dictionary* CPDF_Object::GetDict() { - return nullptr; +RetainPtr<const CPDF_Dictionary> CPDF_Object::GetDict() const { + return pdfium::WrapRetain(GetDictInternal()); } -const CPDF_Dictionary* CPDF_Object::GetDict() const { +RetainPtr<CPDF_Dictionary> CPDF_Object::GetMutableDict() { + return pdfium::WrapRetain(const_cast<CPDF_Dictionary*>(GetDictInternal())); +} + +const CPDF_Dictionary* CPDF_Object::GetDictInternal() const { return nullptr; } @@ -70,107 +91,79 @@ NOTREACHED(); } -bool CPDF_Object::IsArray() const { - return false; -} - -bool CPDF_Object::IsBoolean() const { - return false; -} - -bool CPDF_Object::IsDictionary() const { - return false; -} - -bool CPDF_Object::IsName() const { - return false; -} - -bool CPDF_Object::IsNumber() const { - return false; -} - -bool CPDF_Object::IsReference() const { - return false; -} - -bool CPDF_Object::IsStream() const { - return false; -} - -bool CPDF_Object::IsString() const { - return false; -} - -bool CPDF_Object::IsNull() const { - return false; -} - -CPDF_Array* CPDF_Object::AsArray() { +CPDF_Array* CPDF_Object::AsMutableArray() { return nullptr; } const CPDF_Array* CPDF_Object::AsArray() const { - return nullptr; + return const_cast<CPDF_Object*>(this)->AsMutableArray(); } -CPDF_Boolean* CPDF_Object::AsBoolean() { +CPDF_Boolean* CPDF_Object::AsMutableBoolean() { return nullptr; } const CPDF_Boolean* CPDF_Object::AsBoolean() const { - return nullptr; + return const_cast<CPDF_Object*>(this)->AsMutableBoolean(); } -CPDF_Dictionary* CPDF_Object::AsDictionary() { +CPDF_Dictionary* CPDF_Object::AsMutableDictionary() { return nullptr; } const CPDF_Dictionary* CPDF_Object::AsDictionary() const { - return nullptr; + return const_cast<CPDF_Object*>(this)->AsMutableDictionary(); } -CPDF_Name* CPDF_Object::AsName() { +CPDF_Name* CPDF_Object::AsMutableName() { return nullptr; } const CPDF_Name* CPDF_Object::AsName() const { + return const_cast<CPDF_Object*>(this)->AsMutableName(); +} + +CPDF_Null* CPDF_Object::AsMutableNull() { return nullptr; } -CPDF_Number* CPDF_Object::AsNumber() { +const CPDF_Null* CPDF_Object::AsNull() const { + return const_cast<CPDF_Object*>(this)->AsMutableNull(); +} + +CPDF_Number* CPDF_Object::AsMutableNumber() { return nullptr; } const CPDF_Number* CPDF_Object::AsNumber() const { - return nullptr; + return const_cast<CPDF_Object*>(this)->AsMutableNumber(); } -CPDF_Reference* CPDF_Object::AsReference() { +CPDF_Reference* CPDF_Object::AsMutableReference() { return nullptr; } const CPDF_Reference* CPDF_Object::AsReference() const { - return nullptr; + return const_cast<CPDF_Object*>(this)->AsMutableReference(); } -CPDF_Stream* CPDF_Object::AsStream() { +CPDF_Stream* CPDF_Object::AsMutableStream() { return nullptr; } const CPDF_Stream* CPDF_Object::AsStream() const { - return nullptr; + return const_cast<CPDF_Object*>(this)->AsMutableStream(); } -CPDF_String* CPDF_Object::AsString() { +CPDF_String* CPDF_Object::AsMutableString() { return nullptr; } const CPDF_String* CPDF_Object::AsString() const { - return nullptr; + return const_cast<CPDF_Object*>(this)->AsMutableString(); } -RetainPtr<CPDF_Object> CPDF_Object::MakeReference( +RetainPtr<CPDF_Reference> CPDF_Object::MakeReference( CPDF_IndirectObjectHolder* holder) const { if (IsInline()) { NOTREACHED();
diff --git a/core/fpdfapi/parser/cpdf_object.h b/core/fpdfapi/parser/cpdf_object.h index 77810ca..4793b61 100644 --- a/core/fpdfapi/parser/cpdf_object.h +++ b/core/fpdfapi/parser/cpdf_object.h
@@ -1,4 +1,4 @@ -// Copyright 2016 PDFium Authors. All rights reserved. +// Copyright 2016 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -7,12 +7,13 @@ #ifndef CORE_FPDFAPI_PARSER_CPDF_OBJECT_H_ #define CORE_FPDFAPI_PARSER_CPDF_OBJECT_H_ -#include <memory> +#include <stdint.h> + #include <set> #include <type_traits> #include "core/fxcrt/fx_string.h" -#include "core/fxcrt/fx_system.h" +#include "core/fxcrt/retain_ptr.h" class CPDF_Array; class CPDF_Boolean; @@ -27,9 +28,28 @@ class CPDF_String; class IFX_ArchiveStream; +// ISO 32000-1:2008 defines PDF objects. When CPDF_Parser parses a PDF object, +// it represents the PDF object using CPDF_Objects. Take this PDF object for +// example: +// +// 4 0 obj << +// /Type /Pages +// /Count 1 +// /Kids [9 0 R] +// >> +// +// Multiple CPDF_Objects instances are necessary to represent this PDF object: +// 1) A CPDF_Dictionary with object number 4 that contains 3 elements. +// 2) A CPDF_Name for /Pages. +// 3) A CPDF_Number for the count of 1. +// 4) A CPDF_Array for [9 0 R], which contains 1 element. +// 5) A CPDF_Reference that references object 9 0. +// +// CPDF_Object (1) has an object number of 4. All the other CPDF_Objects are +// inline objects. CPDF_Object represent that by using an object number of 0. class CPDF_Object : public Retainable { public: - static const uint32_t kInvalidObjNum = static_cast<uint32_t>(-1); + static constexpr uint32_t kInvalidObjNum = static_cast<uint32_t>(-1); enum Type { kBoolean = 1, kNumber, @@ -42,57 +62,38 @@ kReference }; - virtual Type GetType() const = 0; uint32_t GetObjNum() const { return m_ObjNum; } void SetObjNum(uint32_t objnum) { m_ObjNum = objnum; } uint32_t GetGenNum() const { return m_GenNum; } void SetGenNum(uint32_t gennum) { m_GenNum = gennum; } bool IsInline() const { return m_ObjNum == 0; } + uint64_t KeyForCache() const; + + virtual Type GetType() const = 0; // Create a deep copy of the object. virtual RetainPtr<CPDF_Object> Clone() const = 0; // Create a deep copy of the object except any reference object be // copied to the object it points to directly. - virtual RetainPtr<CPDF_Object> CloneDirectObject() const; + RetainPtr<CPDF_Object> CloneDirectObject() const; - virtual CPDF_Object* GetDirect(); - virtual const CPDF_Object* GetDirect() const; virtual ByteString GetString() const; virtual WideString GetUnicodeText() const; virtual float GetNumber() const; virtual int GetInteger() const; - virtual CPDF_Dictionary* GetDict(); - virtual const CPDF_Dictionary* GetDict() const; virtual void SetString(const ByteString& str); - virtual bool IsArray() const; - virtual bool IsBoolean() const; - virtual bool IsDictionary() const; - virtual bool IsName() const; - virtual bool IsNumber() const; - virtual bool IsReference() const; - virtual bool IsStream() const; - virtual bool IsString() const; - virtual bool IsNull() const; - - virtual CPDF_Array* AsArray(); - virtual const CPDF_Array* AsArray() const; - virtual CPDF_Boolean* AsBoolean(); - virtual const CPDF_Boolean* AsBoolean() const; - virtual CPDF_Dictionary* AsDictionary(); - virtual const CPDF_Dictionary* AsDictionary() const; - virtual CPDF_Name* AsName(); - virtual const CPDF_Name* AsName() const; - virtual CPDF_Number* AsNumber(); - virtual const CPDF_Number* AsNumber() const; - virtual CPDF_Reference* AsReference(); - virtual const CPDF_Reference* AsReference() const; - virtual CPDF_Stream* AsStream(); - virtual const CPDF_Stream* AsStream() const; - virtual CPDF_String* AsString(); - virtual const CPDF_String* AsString() const; + virtual CPDF_Array* AsMutableArray(); + virtual CPDF_Boolean* AsMutableBoolean(); + virtual CPDF_Dictionary* AsMutableDictionary(); + virtual CPDF_Name* AsMutableName(); + virtual CPDF_Null* AsMutableNull(); + virtual CPDF_Number* AsMutableNumber(); + virtual CPDF_Reference* AsMutableReference(); + virtual CPDF_Stream* AsMutableStream(); + virtual CPDF_String* AsMutableString(); virtual bool WriteTo(IFX_ArchiveStream* archive, const CPDF_Encryptor* encryptor) const = 0; @@ -109,14 +110,46 @@ // Return a reference to itself. // The object must be direct (!IsInlined). - virtual RetainPtr<CPDF_Object> MakeReference( + virtual RetainPtr<CPDF_Reference> MakeReference( CPDF_IndirectObjectHolder* holder) const; + RetainPtr<const CPDF_Object> GetDirect() const; // Wraps virtual method. + RetainPtr<CPDF_Object> GetMutableDirect(); // Wraps virtual method. + RetainPtr<const CPDF_Dictionary> GetDict() const; // Wraps virtual method. + RetainPtr<CPDF_Dictionary> GetMutableDict(); // Wraps virtual method. + + // Const methods wrapping non-const virtual As*() methods. + const CPDF_Array* AsArray() const; + const CPDF_Boolean* AsBoolean() const; + const CPDF_Dictionary* AsDictionary() const; + const CPDF_Name* AsName() const; + const CPDF_Null* AsNull() const; + const CPDF_Number* AsNumber() const; + const CPDF_Reference* AsReference() const; + const CPDF_Stream* AsStream() const; + const CPDF_String* AsString() const; + + // Type-testing methods merely wrap As*() methods. + bool IsArray() const { return !!AsArray(); } + bool IsBoolean() const { return !!AsBoolean(); } + bool IsDictionary() const { return !!AsDictionary(); } + bool IsName() const { return !!AsName(); } + bool IsNull() const { return !!AsNull(); } + bool IsNumber() const { return !!AsNumber(); } + bool IsReference() const { return !!AsReference(); } + bool IsStream() const { return !!AsStream(); } + bool IsString() const { return !!AsString(); } + protected: + friend class CPDF_Dictionary; + friend class CPDF_Reference; + CPDF_Object() = default; CPDF_Object(const CPDF_Object& src) = delete; ~CPDF_Object() override; + virtual const CPDF_Object* GetDirectInternal() const; + virtual const CPDF_Dictionary* GetDictInternal() const; RetainPtr<CPDF_Object> CloneObjectNonCyclic(bool bDirect) const; uint32_t m_ObjNum = 0; @@ -125,10 +158,10 @@ template <typename T> struct CanInternStrings { - static const bool value = std::is_same<T, CPDF_Array>::value || - std::is_same<T, CPDF_Dictionary>::value || - std::is_same<T, CPDF_Name>::value || - std::is_same<T, CPDF_String>::value; + static constexpr bool value = std::is_same<T, CPDF_Array>::value || + std::is_same<T, CPDF_Dictionary>::value || + std::is_same<T, CPDF_Name>::value || + std::is_same<T, CPDF_String>::value; }; #endif // CORE_FPDFAPI_PARSER_CPDF_OBJECT_H_
diff --git a/core/fpdfapi/parser/cpdf_object_avail.cpp b/core/fpdfapi/parser/cpdf_object_avail.cpp index 1dc5125..8bb3473 100644 --- a/core/fpdfapi/parser/cpdf_object_avail.cpp +++ b/core/fpdfapi/parser/cpdf_object_avail.cpp
@@ -1,4 +1,4 @@ -// Copyright 2017 PDFium Authors. All rights reserved. +// Copyright 2017 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -11,42 +11,43 @@ #include "core/fpdfapi/parser/cpdf_object_walker.h" #include "core/fpdfapi/parser/cpdf_read_validator.h" #include "core/fpdfapi/parser/cpdf_reference.h" -#include "third_party/base/ptr_util.h" +#include "third_party/base/check.h" +#include "third_party/base/containers/contains.h" -CPDF_ObjectAvail::CPDF_ObjectAvail( - const RetainPtr<CPDF_ReadValidator>& validator, - CPDF_IndirectObjectHolder* holder, - CPDF_Object* root) - : validator_(validator), holder_(holder), root_(root) { - ASSERT(validator_); - ASSERT(holder); - ASSERT(root_); +CPDF_ObjectAvail::CPDF_ObjectAvail(RetainPtr<CPDF_ReadValidator> validator, + CPDF_IndirectObjectHolder* holder, + RetainPtr<const CPDF_Object> root) + : validator_(std::move(validator)), + holder_(holder), + root_(std::move(root)) { + DCHECK(validator_); + DCHECK(holder); + DCHECK(root_); if (!root_->IsInline()) parsed_objnums_.insert(root_->GetObjNum()); } -CPDF_ObjectAvail::CPDF_ObjectAvail( - const RetainPtr<CPDF_ReadValidator>& validator, - CPDF_IndirectObjectHolder* holder, - uint32_t obj_num) - : validator_(validator), +CPDF_ObjectAvail::CPDF_ObjectAvail(RetainPtr<CPDF_ReadValidator> validator, + CPDF_IndirectObjectHolder* holder, + uint32_t obj_num) + : validator_(std::move(validator)), holder_(holder), root_(pdfium::MakeRetain<CPDF_Reference>(holder, obj_num)) { - ASSERT(validator_); - ASSERT(holder); + DCHECK(validator_); + DCHECK(holder); } -CPDF_ObjectAvail::~CPDF_ObjectAvail() {} +CPDF_ObjectAvail::~CPDF_ObjectAvail() = default; CPDF_DataAvail::DocAvailStatus CPDF_ObjectAvail::CheckAvail() { if (!LoadRootObject()) - return CPDF_DataAvail::DocAvailStatus::DataNotAvailable; + return CPDF_DataAvail::kDataNotAvailable; if (CheckObjects()) { CleanMemory(); - return CPDF_DataAvail::DocAvailStatus::DataAvailable; + return CPDF_DataAvail::kDataAvailable; } - return CPDF_DataAvail::DocAvailStatus::DataNotAvailable; + return CPDF_DataAvail::kDataNotAvailable; } bool CPDF_ObjectAvail::LoadRootObject() { @@ -60,16 +61,17 @@ return true; } - const CPDF_ReadValidator::Session parse_session(validator_); - CPDF_Object* direct = holder_->GetOrParseIndirectObject(ref_obj_num); + CPDF_ReadValidator::ScopedSession parse_session(validator_); + RetainPtr<CPDF_Object> direct = + holder_->GetOrParseIndirectObject(ref_obj_num); if (validator_->has_read_problems()) return false; parsed_objnums_.insert(ref_obj_num); - root_.Reset(direct); + root_ = std::move(direct); } std::stack<uint32_t> non_parsed_objects_in_root; - if (AppendObjectSubRefs(root_.Get(), &non_parsed_objects_in_root)) { + if (AppendObjectSubRefs(root_, &non_parsed_objects_in_root)) { non_parsed_objects_ = std::move(non_parsed_objects_in_root); return true; } @@ -90,13 +92,14 @@ if (!checked_objects.insert(obj_num).second) continue; - const CPDF_ReadValidator::Session parse_session(validator_); - const CPDF_Object* direct = holder_->GetOrParseIndirectObject(obj_num); + CPDF_ReadValidator::ScopedSession parse_session(validator_); + RetainPtr<const CPDF_Object> direct = + holder_->GetOrParseIndirectObject(obj_num); if (direct == root_) continue; if (validator_->has_read_problems() || - !AppendObjectSubRefs(direct, &objects_to_check)) { + !AppendObjectSubRefs(std::move(direct), &objects_to_check)) { non_parsed_objects_.push(obj_num); continue; } @@ -105,21 +108,21 @@ return non_parsed_objects_.empty(); } -bool CPDF_ObjectAvail::AppendObjectSubRefs(const CPDF_Object* object, +bool CPDF_ObjectAvail::AppendObjectSubRefs(RetainPtr<const CPDF_Object> object, std::stack<uint32_t>* refs) const { - ASSERT(refs); + DCHECK(refs); if (!object) return true; - CPDF_ObjectWalker walker(object); - while (const CPDF_Object* obj = walker.GetNext()) { - const CPDF_ReadValidator::Session parse_session(validator_); + CPDF_ObjectWalker walker(std::move(object)); + while (RetainPtr<const CPDF_Object> obj = walker.GetNext()) { + CPDF_ReadValidator::ScopedSession parse_session(validator_); // Skip if this object if it's an inlined root, the parent object or // explicitily excluded. const bool skip = (walker.GetParent() && obj == root_) || walker.dictionary_key() == "Parent" || - (obj != root_ && ExcludeObject(obj)); + (obj != root_ && ExcludeObject(obj.Get())); // We need to parse the object before we can do the exclusion check. // This is because the exclusion check may check against a referenced @@ -148,5 +151,5 @@ } bool CPDF_ObjectAvail::HasObjectParsed(uint32_t obj_num) const { - return parsed_objnums_.count(obj_num) > 0; + return pdfium::Contains(parsed_objnums_, obj_num); }
diff --git a/core/fpdfapi/parser/cpdf_object_avail.h b/core/fpdfapi/parser/cpdf_object_avail.h index 901fb17..df7360d 100644 --- a/core/fpdfapi/parser/cpdf_object_avail.h +++ b/core/fpdfapi/parser/cpdf_object_avail.h
@@ -1,4 +1,4 @@ -// Copyright 2017 PDFium Authors. All rights reserved. +// Copyright 2017 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -13,17 +13,16 @@ #include "core/fxcrt/unowned_ptr.h" class CPDF_Object; -class CPDF_Reference; class CPDF_IndirectObjectHolder; class CPDF_ReadValidator; // Helper for check availability of object tree. class CPDF_ObjectAvail { public: - CPDF_ObjectAvail(const RetainPtr<CPDF_ReadValidator>& validator, + CPDF_ObjectAvail(RetainPtr<CPDF_ReadValidator> validator, CPDF_IndirectObjectHolder* holder, - CPDF_Object* root); - CPDF_ObjectAvail(const RetainPtr<CPDF_ReadValidator>& validator, + RetainPtr<const CPDF_Object> root); + CPDF_ObjectAvail(RetainPtr<CPDF_ReadValidator> validator, CPDF_IndirectObjectHolder* holder, uint32_t obj_num); virtual ~CPDF_ObjectAvail(); @@ -36,14 +35,14 @@ private: bool LoadRootObject(); bool CheckObjects(); - bool AppendObjectSubRefs(const CPDF_Object* object, + bool AppendObjectSubRefs(RetainPtr<const CPDF_Object> object, std::stack<uint32_t>* refs) const; void CleanMemory(); bool HasObjectParsed(uint32_t obj_num) const; - RetainPtr<CPDF_ReadValidator> validator_; - UnownedPtr<CPDF_IndirectObjectHolder> holder_; - RetainPtr<CPDF_Object> root_; + RetainPtr<CPDF_ReadValidator> const validator_; + UnownedPtr<CPDF_IndirectObjectHolder> const holder_; + RetainPtr<const CPDF_Object> root_; std::set<uint32_t> parsed_objnums_; std::stack<uint32_t> non_parsed_objects_; };
diff --git a/core/fpdfapi/parser/cpdf_object_avail_unittest.cpp b/core/fpdfapi/parser/cpdf_object_avail_unittest.cpp index f27ae63..97eb3d6 100644 --- a/core/fpdfapi/parser/cpdf_object_avail_unittest.cpp +++ b/core/fpdfapi/parser/cpdf_object_avail_unittest.cpp
@@ -1,11 +1,10 @@ -// Copyright 2017 PDFium Authors. All rights reserved. +// Copyright 2017 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "core/fpdfapi/parser/cpdf_object_avail.h" #include <map> -#include <memory> #include <utility> #include "core/fpdfapi/parser/cpdf_array.h" @@ -17,22 +16,22 @@ #include "core/fxcrt/fx_stream.h" #include "testing/gtest/include/gtest/gtest.h" #include "testing/invalid_seekable_read_stream.h" -#include "third_party/base/ptr_util.h" +#include "third_party/base/check.h" +#include "third_party/base/notreached.h" namespace { class TestReadValidator final : public CPDF_ReadValidator { public: - template <typename T, typename... Args> - friend RetainPtr<T> pdfium::MakeRetain(Args&&... args); + CONSTRUCT_VIA_MAKE_RETAIN; - void SimulateReadError() { ReadBlockAtOffset(nullptr, 0, 1); } + void SimulateReadError() { ReadBlockAtOffset({}, 0); } private: TestReadValidator() : CPDF_ReadValidator(pdfium::MakeRetain<InvalidSeekableReadStream>(100), nullptr) {} - ~TestReadValidator() override {} + ~TestReadValidator() override = default; }; class TestHolder final : public CPDF_IndirectObjectHolder { @@ -42,10 +41,10 @@ Available, }; TestHolder() : validator_(pdfium::MakeRetain<TestReadValidator>()) {} - ~TestHolder() override {} + ~TestHolder() override = default; // CPDF_IndirectObjectHolder overrides: - CPDF_Object* GetOrParseIndirectObject(uint32_t objnum) override { + RetainPtr<CPDF_Object> ParseIndirectObject(uint32_t objnum) override { auto it = objects_data_.find(objnum); if (it == objects_data_.end()) return nullptr; @@ -55,7 +54,7 @@ validator_->SimulateReadError(); return nullptr; } - return obj_data.object.Get(); + return obj_data.object; } RetainPtr<CPDF_ReadValidator> GetValidator() { return validator_; } @@ -66,13 +65,13 @@ ObjectData object_data; object_data.object = std::move(object); object_data.state = state; - ASSERT(objects_data_.find(objnum) == objects_data_.end()); + DCHECK(objects_data_.find(objnum) == objects_data_.end()); objects_data_[objnum] = std::move(object_data); } void SetObjectState(uint32_t objnum, ObjectState state) { auto it = objects_data_.find(objnum); - ASSERT(it != objects_data_.end()); + DCHECK(it != objects_data_.end()); ObjectData& obj_data = it->second; obj_data.state = state; } @@ -96,7 +95,7 @@ class CPDF_ObjectAvailFailOnExclude final : public CPDF_ObjectAvail { public: using CPDF_ObjectAvail::CPDF_ObjectAvail; - ~CPDF_ObjectAvailFailOnExclude() override {} + ~CPDF_ObjectAvailFailOnExclude() override = default; bool ExcludeObject(const CPDF_Object* object) const override { NOTREACHED(); return false; @@ -106,7 +105,7 @@ class CPDF_ObjectAvailExcludeArray final : public CPDF_ObjectAvail { public: using CPDF_ObjectAvail::CPDF_ObjectAvail; - ~CPDF_ObjectAvailExcludeArray() override {} + ~CPDF_ObjectAvailExcludeArray() override = default; bool ExcludeObject(const CPDF_Object* object) const override { return object->IsArray(); } @@ -115,49 +114,46 @@ class CPDF_ObjectAvailExcludeTypeKey final : public CPDF_ObjectAvail { public: using CPDF_ObjectAvail::CPDF_ObjectAvail; - ~CPDF_ObjectAvailExcludeTypeKey() override {} + ~CPDF_ObjectAvailExcludeTypeKey() override = default; bool ExcludeObject(const CPDF_Object* object) const override { // The value of "Type" may be reference, and if it is not available, we can // incorrect filter objects. // In this case CPDF_ObjectAvail should wait availability of this item and // call ExcludeObject again. return object->IsDictionary() && - object->GetDict()->GetStringFor("Type") == "Exclude me"; + object->GetDict()->GetByteStringFor("Type") == "Exclude me"; } }; } // namespace -TEST(CPDF_ObjectAvailTest, OneObject) { +TEST(ObjectAvailTest, OneObject) { TestHolder holder; holder.AddObject(1, pdfium::MakeRetain<CPDF_String>(nullptr, "string", false), TestHolder::ObjectState::Unavailable); CPDF_ObjectAvail avail(holder.GetValidator(), &holder, 1); - EXPECT_EQ(CPDF_DataAvail::DocAvailStatus::DataNotAvailable, - avail.CheckAvail()); + EXPECT_EQ(CPDF_DataAvail::kDataNotAvailable, avail.CheckAvail()); holder.SetObjectState(1, TestHolder::ObjectState::Available); - EXPECT_EQ(CPDF_DataAvail::DocAvailStatus::DataAvailable, avail.CheckAvail()); + EXPECT_EQ(CPDF_DataAvail::kDataAvailable, avail.CheckAvail()); } -TEST(CPDF_ObjectAvailTest, OneReferencedObject) { +TEST(ObjectAvailTest, OneReferencedObject) { TestHolder holder; holder.AddObject(1, pdfium::MakeRetain<CPDF_Reference>(&holder, 2), TestHolder::ObjectState::Unavailable); holder.AddObject(2, pdfium::MakeRetain<CPDF_String>(nullptr, "string", false), TestHolder::ObjectState::Unavailable); CPDF_ObjectAvail avail(holder.GetValidator(), &holder, 1); - EXPECT_EQ(CPDF_DataAvail::DocAvailStatus::DataNotAvailable, - avail.CheckAvail()); + EXPECT_EQ(CPDF_DataAvail::kDataNotAvailable, avail.CheckAvail()); holder.SetObjectState(1, TestHolder::ObjectState::Available); - EXPECT_EQ(CPDF_DataAvail::DocAvailStatus::DataNotAvailable, - avail.CheckAvail()); + EXPECT_EQ(CPDF_DataAvail::kDataNotAvailable, avail.CheckAvail()); holder.SetObjectState(2, TestHolder::ObjectState::Available); - EXPECT_EQ(CPDF_DataAvail::DocAvailStatus::DataAvailable, avail.CheckAvail()); + EXPECT_EQ(CPDF_DataAvail::kDataAvailable, avail.CheckAvail()); } -TEST(CPDF_ObjectAvailTest, CycledReferences) { +TEST(ObjectAvailTest, CycledReferences) { TestHolder holder; holder.AddObject(1, pdfium::MakeRetain<CPDF_Reference>(&holder, 2), TestHolder::ObjectState::Unavailable); @@ -167,48 +163,44 @@ TestHolder::ObjectState::Unavailable); CPDF_ObjectAvail avail(holder.GetValidator(), &holder, 1); - EXPECT_EQ(CPDF_DataAvail::DocAvailStatus::DataNotAvailable, - avail.CheckAvail()); + EXPECT_EQ(CPDF_DataAvail::kDataNotAvailable, avail.CheckAvail()); holder.SetObjectState(1, TestHolder::ObjectState::Available); - EXPECT_EQ(CPDF_DataAvail::DocAvailStatus::DataNotAvailable, - avail.CheckAvail()); + EXPECT_EQ(CPDF_DataAvail::kDataNotAvailable, avail.CheckAvail()); holder.SetObjectState(2, TestHolder::ObjectState::Available); - EXPECT_EQ(CPDF_DataAvail::DocAvailStatus::DataNotAvailable, - avail.CheckAvail()); + EXPECT_EQ(CPDF_DataAvail::kDataNotAvailable, avail.CheckAvail()); holder.SetObjectState(3, TestHolder::ObjectState::Available); - EXPECT_EQ(CPDF_DataAvail::DocAvailStatus::DataAvailable, avail.CheckAvail()); + EXPECT_EQ(CPDF_DataAvail::kDataAvailable, avail.CheckAvail()); } -TEST(CPDF_ObjectAvailTest, DoNotCheckParent) { +TEST(ObjectAvailTest, DoNotCheckParent) { TestHolder holder; holder.AddObject(1, pdfium::MakeRetain<CPDF_Dictionary>(), TestHolder::ObjectState::Unavailable); holder.AddObject(2, pdfium::MakeRetain<CPDF_Dictionary>(), TestHolder::ObjectState::Unavailable); - holder.GetTestObject(2)->GetDict()->SetNewFor<CPDF_Reference>("Parent", - &holder, 1); + holder.GetTestObject(2)->GetMutableDict()->SetNewFor<CPDF_Reference>( + "Parent", &holder, 1); CPDF_ObjectAvail avail(holder.GetValidator(), &holder, 2); - EXPECT_EQ(CPDF_DataAvail::DocAvailStatus::DataNotAvailable, - avail.CheckAvail()); + EXPECT_EQ(CPDF_DataAvail::kDataNotAvailable, avail.CheckAvail()); holder.SetObjectState(2, TestHolder::ObjectState::Available); // Object should be available in case when "Parent" object is unavailable. - EXPECT_EQ(CPDF_DataAvail::DocAvailStatus::DataAvailable, avail.CheckAvail()); + EXPECT_EQ(CPDF_DataAvail::kDataAvailable, avail.CheckAvail()); } -TEST(CPDF_ObjectAvailTest, Generic) { +TEST(ObjectAvailTest, Generic) { TestHolder holder; const uint32_t kDepth = 100; for (uint32_t i = 1; i < kDepth; ++i) { holder.AddObject(i, pdfium::MakeRetain<CPDF_Dictionary>(), TestHolder::ObjectState::Unavailable); // Add ref to next dictionary. - holder.GetTestObject(i)->GetDict()->SetNewFor<CPDF_Reference>( + holder.GetTestObject(i)->GetMutableDict()->SetNewFor<CPDF_Reference>( "Child", &holder, i + 1); } // Add final object @@ -217,40 +209,40 @@ CPDF_ObjectAvail avail(holder.GetValidator(), &holder, 1); for (uint32_t i = 1; i <= kDepth; ++i) { - EXPECT_EQ(CPDF_DataAvail::DocAvailStatus::DataNotAvailable, - avail.CheckAvail()); + EXPECT_EQ(CPDF_DataAvail::kDataNotAvailable, avail.CheckAvail()); holder.SetObjectState(i, TestHolder::ObjectState::Available); } - EXPECT_EQ(CPDF_DataAvail::DocAvailStatus::DataAvailable, avail.CheckAvail()); + EXPECT_EQ(CPDF_DataAvail::kDataAvailable, avail.CheckAvail()); } -TEST(CPDF_ObjectAvailTest, NotExcludeRoot) { +TEST(ObjectAvailTest, NotExcludeRoot) { TestHolder holder; holder.AddObject(1, pdfium::MakeRetain<CPDF_Dictionary>(), TestHolder::ObjectState::Available); CPDF_ObjectAvailFailOnExclude avail(holder.GetValidator(), &holder, 1); - EXPECT_EQ(CPDF_DataAvail::DocAvailStatus::DataAvailable, avail.CheckAvail()); + EXPECT_EQ(CPDF_DataAvail::kDataAvailable, avail.CheckAvail()); } -TEST(CPDF_ObjectAvailTest, NotExcludeReferedRoot) { +TEST(ObjectAvailTest, NotExcludeReferedRoot) { TestHolder holder; holder.AddObject(1, pdfium::MakeRetain<CPDF_Reference>(&holder, 2), TestHolder::ObjectState::Available); holder.AddObject(2, pdfium::MakeRetain<CPDF_Dictionary>(), TestHolder::ObjectState::Available); CPDF_ObjectAvailFailOnExclude avail(holder.GetValidator(), &holder, 1); - EXPECT_EQ(CPDF_DataAvail::DocAvailStatus::DataAvailable, avail.CheckAvail()); + EXPECT_EQ(CPDF_DataAvail::kDataAvailable, avail.CheckAvail()); } -TEST(CPDF_ObjectAvailTest, Exclude) { +TEST(ObjectAvailTest, Exclude) { TestHolder holder; holder.AddObject(1, pdfium::MakeRetain<CPDF_Dictionary>(), TestHolder::ObjectState::Available); - holder.GetTestObject(1)->GetDict()->SetNewFor<CPDF_Reference>("ArrayRef", - &holder, 2); + holder.GetTestObject(1)->GetMutableDict()->SetNewFor<CPDF_Reference>( + "ArrayRef", &holder, 2); holder.AddObject(2, pdfium::MakeRetain<CPDF_Array>(), TestHolder::ObjectState::Available); - holder.GetTestObject(2)->AsArray()->AddNew<CPDF_Reference>(&holder, 2); + holder.GetTestObject(2)->AsMutableArray()->AppendNew<CPDF_Reference>(&holder, + 2); // Add string, which is refered by array item. It is should not be checked. holder.AddObject( @@ -258,28 +250,28 @@ pdfium::MakeRetain<CPDF_String>(nullptr, "Not available string", false), TestHolder::ObjectState::Unavailable); CPDF_ObjectAvailExcludeArray avail(holder.GetValidator(), &holder, 1); - EXPECT_EQ(CPDF_DataAvail::DocAvailStatus::DataAvailable, avail.CheckAvail()); + EXPECT_EQ(CPDF_DataAvail::kDataAvailable, avail.CheckAvail()); } -TEST(CPDF_ObjectAvailTest, ReadErrorOnExclude) { +TEST(ObjectAvailTest, ReadErrorOnExclude) { TestHolder holder; holder.AddObject(1, pdfium::MakeRetain<CPDF_Dictionary>(), TestHolder::ObjectState::Available); - holder.GetTestObject(1)->GetDict()->SetNewFor<CPDF_Reference>("DictRef", - &holder, 2); + holder.GetTestObject(1)->GetMutableDict()->SetNewFor<CPDF_Reference>( + "DictRef", &holder, 2); holder.AddObject(2, pdfium::MakeRetain<CPDF_Dictionary>(), TestHolder::ObjectState::Available); - holder.GetTestObject(2)->GetDict()->SetNewFor<CPDF_Reference>("Type", &holder, - 3); + holder.GetTestObject(2)->GetMutableDict()->SetNewFor<CPDF_Reference>( + "Type", &holder, 3); // The value of "Type" key is not available at start holder.AddObject( 3, pdfium::MakeRetain<CPDF_String>(nullptr, "Exclude me", false), TestHolder::ObjectState::Unavailable); - holder.GetTestObject(2)->GetDict()->SetNewFor<CPDF_Reference>("OtherData", - &holder, 4); - // Add string, which is refered by dictionary item. It is should not be + holder.GetTestObject(2)->GetMutableDict()->SetNewFor<CPDF_Reference>( + "OtherData", &holder, 4); + // Add string, which is referred by dictionary item. It is should not be // checked, because the dictionary with it, should be skipped. holder.AddObject( 4, @@ -288,30 +280,29 @@ CPDF_ObjectAvailExcludeTypeKey avail(holder.GetValidator(), &holder, 1); - EXPECT_EQ(CPDF_DataAvail::DocAvailStatus::DataNotAvailable, - avail.CheckAvail()); + EXPECT_EQ(CPDF_DataAvail::kDataNotAvailable, avail.CheckAvail()); // Make "Type" value object available. holder.SetObjectState(3, TestHolder::ObjectState::Available); // Now object should be available, although the object '4' is not available, // because it is in skipped dictionary. - EXPECT_EQ(CPDF_DataAvail::DocAvailStatus::DataAvailable, avail.CheckAvail()); + EXPECT_EQ(CPDF_DataAvail::kDataAvailable, avail.CheckAvail()); } -TEST(CPDF_ObjectAvailTest, IgnoreNotExistsObject) { +TEST(ObjectAvailTest, IgnoreNotExistsObject) { TestHolder holder; holder.AddObject(1, pdfium::MakeRetain<CPDF_Dictionary>(), TestHolder::ObjectState::Available); - holder.GetTestObject(1)->GetDict()->SetNewFor<CPDF_Reference>( + holder.GetTestObject(1)->GetMutableDict()->SetNewFor<CPDF_Reference>( "NotExistsObjRef", &holder, 2); CPDF_ObjectAvail avail(holder.GetValidator(), &holder, 1); // Now object should be available, although the object '2' is not exists. But // all exists in file related data are checked. - EXPECT_EQ(CPDF_DataAvail::DocAvailStatus::DataAvailable, avail.CheckAvail()); + EXPECT_EQ(CPDF_DataAvail::kDataAvailable, avail.CheckAvail()); } -TEST(CPDF_ObjectAvailTest, CheckTwice) { +TEST(ObjectAvailTest, CheckTwice) { TestHolder holder; holder.AddObject(1, pdfium::MakeRetain<CPDF_String>(nullptr, "string", false), TestHolder::ObjectState::Unavailable); @@ -323,27 +314,24 @@ EXPECT_EQ(avail.CheckAvail(), avail.CheckAvail()); } -TEST(CPDF_ObjectAvailTest, SelfReferedInlinedObject) { +TEST(ObjectAvailTest, SelfReferedInlinedObject) { TestHolder holder; holder.AddObject(1, pdfium::MakeRetain<CPDF_Dictionary>(), TestHolder::ObjectState::Available); - holder.GetTestObject(1)->GetDict()->SetNewFor<CPDF_Reference>("Data", &holder, - 2); - auto* root = - holder.GetTestObject(1)->GetDict()->SetNewFor<CPDF_Dictionary>("Dict"); + holder.GetTestObject(1)->GetMutableDict()->SetNewFor<CPDF_Reference>( + "Data", &holder, 2); + auto root = + holder.GetTestObject(1)->GetMutableDict()->SetNewFor<CPDF_Dictionary>( + "Dict"); root->SetNewFor<CPDF_Reference>("Self", &holder, 1); - holder.AddObject(2, pdfium::MakeRetain<CPDF_String>(nullptr, "Data", false), TestHolder::ObjectState::Unavailable); CPDF_ObjectAvail avail(holder.GetValidator(), &holder, root); - - EXPECT_EQ(CPDF_DataAvail::DocAvailStatus::DataNotAvailable, - avail.CheckAvail()); + EXPECT_EQ(CPDF_DataAvail::kDataNotAvailable, avail.CheckAvail()); holder.SetObjectState(2, TestHolder::ObjectState::Available); - - EXPECT_EQ(CPDF_DataAvail::DocAvailStatus::DataAvailable, avail.CheckAvail()); + EXPECT_EQ(CPDF_DataAvail::kDataAvailable, avail.CheckAvail()); }
diff --git a/core/fpdfapi/parser/cpdf_object_stream.cpp b/core/fpdfapi/parser/cpdf_object_stream.cpp index a515dbb..1c5a7b7 100644 --- a/core/fpdfapi/parser/cpdf_object_stream.cpp +++ b/core/fpdfapi/parser/cpdf_object_stream.cpp
@@ -1,4 +1,4 @@ -// Copyright 2018 PDFium Authors. All rights reserved. +// Copyright 2018 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -13,26 +13,26 @@ #include "core/fpdfapi/parser/cpdf_stream.h" #include "core/fpdfapi/parser/cpdf_stream_acc.h" #include "core/fpdfapi/parser/cpdf_syntax_parser.h" -#include "core/fxcrt/cfx_readonlymemorystream.h" +#include "core/fpdfapi/parser/fpdf_parser_utility.h" +#include "core/fxcrt/cfx_read_only_span_stream.h" #include "core/fxcrt/fx_safe_types.h" +#include "third_party/base/check.h" #include "third_party/base/ptr_util.h" -#include "third_party/base/stl_util.h" -// static -bool CPDF_ObjectStream::IsObjectsStreamObject(const CPDF_Object* object) { +namespace { + +bool IsObjectStream(const CPDF_Object* object) { const CPDF_Stream* stream = ToStream(object); if (!stream) return false; - const CPDF_Dictionary* stream_dict = stream->GetDict(); - if (!stream_dict) + // See ISO 32000-1:2008 spec, table 16. + RetainPtr<const CPDF_Dictionary> stream_dict = stream->GetDict(); + if (!ValidateDictType(stream_dict.Get(), "ObjStm")) return false; - if (stream_dict->GetStringFor("Type") != "ObjStm") - return false; - - const CPDF_Number* number_of_objects = - ToNumber(stream_dict->GetObjectFor("N")); + RetainPtr<const CPDF_Number> number_of_objects = + stream_dict->GetNumberFor("N"); if (!number_of_objects || !number_of_objects->IsInteger() || number_of_objects->GetInteger() < 0 || number_of_objects->GetInteger() >= @@ -40,8 +40,8 @@ return false; } - const CPDF_Number* first_object_offset = - ToNumber(stream_dict->GetObjectFor("First")); + RetainPtr<const CPDF_Number> first_object_offset = + stream_dict->GetNumberFor("First"); if (!first_object_offset || !first_object_offset->IsInteger() || first_object_offset->GetInteger() < 0) { return false; @@ -50,56 +50,49 @@ return true; } +} // namespace + // static std::unique_ptr<CPDF_ObjectStream> CPDF_ObjectStream::Create( - const CPDF_Stream* stream) { - if (!IsObjectsStreamObject(stream)) + RetainPtr<const CPDF_Stream> stream) { + if (!IsObjectStream(stream.Get())) return nullptr; - // The ctor of CPDF_ObjectStream is protected. Use WrapUnique instead - // MakeUnique. - return pdfium::WrapUnique(new CPDF_ObjectStream(stream)); + + // Protected constructor. + return pdfium::WrapUnique(new CPDF_ObjectStream(std::move(stream))); } -CPDF_ObjectStream::CPDF_ObjectStream(const CPDF_Stream* obj_stream) - : obj_num_(obj_stream->GetObjNum()), +CPDF_ObjectStream::CPDF_ObjectStream(RetainPtr<const CPDF_Stream> obj_stream) + : stream_acc_(pdfium::MakeRetain<CPDF_StreamAcc>(obj_stream)), first_object_offset_(obj_stream->GetDict()->GetIntegerFor("First")) { - ASSERT(IsObjectsStreamObject(obj_stream)); - if (const auto* extends_ref = - ToReference(obj_stream->GetDict()->GetObjectFor("Extends"))) { - extends_obj_num_ = extends_ref->GetRefObjNum(); - } - Init(obj_stream); + DCHECK(IsObjectStream(obj_stream.Get())); + Init(obj_stream.Get()); } CPDF_ObjectStream::~CPDF_ObjectStream() = default; -bool CPDF_ObjectStream::HasObject(uint32_t obj_number) const { - return pdfium::ContainsKey(objects_offsets_, obj_number); -} - RetainPtr<CPDF_Object> CPDF_ObjectStream::ParseObject( CPDF_IndirectObjectHolder* pObjList, - uint32_t obj_number) const { - const auto it = objects_offsets_.find(obj_number); - if (it == objects_offsets_.end()) + uint32_t obj_number, + uint32_t archive_obj_index) const { + if (archive_obj_index >= object_info_.size()) return nullptr; - RetainPtr<CPDF_Object> result = ParseObjectAtOffset(pObjList, it->second); - if (!result) + const auto& info = object_info_[archive_obj_index]; + if (info.obj_num != obj_number) return nullptr; - result->SetObjNum(obj_number); + RetainPtr<CPDF_Object> result = + ParseObjectAtOffset(pObjList, info.obj_offset); + if (result) + result->SetObjNum(obj_number); return result; } void CPDF_ObjectStream::Init(const CPDF_Stream* stream) { - { - auto stream_acc = pdfium::MakeRetain<CPDF_StreamAcc>(stream); - stream_acc->LoadAllDataFiltered(); - const uint32_t data_size = stream_acc->GetSize(); - data_stream_ = pdfium::MakeRetain<CFX_ReadOnlyMemoryStream>( - stream_acc->DetachData(), data_size); - } + stream_acc_->LoadAllDataFiltered(); + data_stream_ = + pdfium::MakeRetain<CFX_ReadOnlySpanStream>(stream_acc_->GetSpan()); CPDF_SyntaxParser syntax(data_stream_); const int object_count = stream->GetDict()->GetIntegerFor("N"); @@ -112,7 +105,7 @@ if (!obj_num) continue; - objects_offsets_[obj_num] = obj_offset; + object_info_.emplace_back(obj_num, obj_offset); } }
diff --git a/core/fpdfapi/parser/cpdf_object_stream.h b/core/fpdfapi/parser/cpdf_object_stream.h index 2fa1634..cfa0737 100644 --- a/core/fpdfapi/parser/cpdf_object_stream.h +++ b/core/fpdfapi/parser/cpdf_object_stream.h
@@ -1,54 +1,60 @@ -// Copyright 2018 PDFium Authors. All rights reserved. +// Copyright 2018 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #ifndef CORE_FPDFAPI_PARSER_CPDF_OBJECT_STREAM_H_ #define CORE_FPDFAPI_PARSER_CPDF_OBJECT_STREAM_H_ -#include <map> #include <memory> +#include <vector> #include "core/fpdfapi/parser/cpdf_object.h" #include "core/fxcrt/retain_ptr.h" class CPDF_IndirectObjectHolder; class CPDF_Stream; +class CPDF_StreamAcc; class IFX_SeekableReadStream; // Implementation of logic of PDF "Object Streams". -// See "PDF 32000-1:2008" Spec. section 7.5.7. +// See ISO 32000-1:2008 spec, section 7.5.7. class CPDF_ObjectStream { public: - static bool IsObjectsStreamObject(const CPDF_Object* object); + struct ObjectInfo { + ObjectInfo(uint32_t obj_num, uint32_t obj_offset) + : obj_num(obj_num), obj_offset(obj_offset) {} - static std::unique_ptr<CPDF_ObjectStream> Create(const CPDF_Stream* stream); + bool operator==(const ObjectInfo& that) const { + return obj_num == that.obj_num && obj_offset == that.obj_offset; + } + + uint32_t obj_num; + uint32_t obj_offset; + }; + + static std::unique_ptr<CPDF_ObjectStream> Create( + RetainPtr<const CPDF_Stream> stream); ~CPDF_ObjectStream(); - uint32_t obj_num() const { return obj_num_; } - uint32_t extends_obj_num() const { return extends_obj_num_; } - - bool HasObject(uint32_t obj_number) const; RetainPtr<CPDF_Object> ParseObject(CPDF_IndirectObjectHolder* pObjList, - uint32_t obj_number) const; - const std::map<uint32_t, uint32_t>& objects_offsets() const { - return objects_offsets_; - } + uint32_t obj_number, + uint32_t archive_obj_index) const; + const std::vector<ObjectInfo>& object_info() const { return object_info_; } - protected: - explicit CPDF_ObjectStream(const CPDF_Stream* stream); + private: + explicit CPDF_ObjectStream(RetainPtr<const CPDF_Stream> stream); void Init(const CPDF_Stream* stream); RetainPtr<CPDF_Object> ParseObjectAtOffset( CPDF_IndirectObjectHolder* pObjList, uint32_t object_offset) const; - uint32_t obj_num_ = CPDF_Object::kInvalidObjNum; - uint32_t extends_obj_num_ = CPDF_Object::kInvalidObjNum; - + // Must outlive `data_stream_`. + RetainPtr<CPDF_StreamAcc> const stream_acc_; RetainPtr<IFX_SeekableReadStream> data_stream_; int first_object_offset_ = 0; - std::map<uint32_t, uint32_t> objects_offsets_; + std::vector<ObjectInfo> object_info_; }; #endif // CORE_FPDFAPI_PARSER_CPDF_OBJECT_STREAM_H_
diff --git a/core/fpdfapi/parser/cpdf_object_stream_unittest.cpp b/core/fpdfapi/parser/cpdf_object_stream_unittest.cpp new file mode 100644 index 0000000..43306f4 --- /dev/null +++ b/core/fpdfapi/parser/cpdf_object_stream_unittest.cpp
@@ -0,0 +1,509 @@ +// Copyright 2021 The PDFium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "core/fpdfapi/parser/cpdf_object_stream.h" + +#include <iterator> +#include <utility> + +#include "core/fpdfapi/parser/cpdf_dictionary.h" +#include "core/fpdfapi/parser/cpdf_indirect_object_holder.h" +#include "core/fpdfapi/parser/cpdf_name.h" +#include "core/fpdfapi/parser/cpdf_number.h" +#include "core/fpdfapi/parser/cpdf_stream.h" +#include "core/fpdfapi/parser/cpdf_string.h" +#include "core/fxcrt/data_vector.h" +#include "testing/gmock/include/gmock/gmock.h" +#include "testing/gtest/include/gtest/gtest.h" + +using testing::ElementsAre; + +namespace { + +constexpr char kNormalStreamContent[] = + "10 0 11 14 12 21<</Name /Foo>>[1 2 3]4"; +constexpr int kNormalStreamContentOffset = 16; +static_assert(kNormalStreamContent[kNormalStreamContentOffset] == '<', + "Wrong offset"); +static_assert(kNormalStreamContent[kNormalStreamContentOffset + 1] == '<', + "Wrong offset"); + +} // namespace + +TEST(ObjectStreamTest, StreamDictNormal) { + auto dict = pdfium::MakeRetain<CPDF_Dictionary>(); + dict->SetNewFor<CPDF_Name>("Type", "ObjStm"); + dict->SetNewFor<CPDF_Number>("N", 3); + dict->SetNewFor<CPDF_Number>("First", kNormalStreamContentOffset); + + ByteStringView contents_view(kNormalStreamContent); + auto stream = pdfium::MakeRetain<CPDF_Stream>( + DataVector<uint8_t>(contents_view.begin(), contents_view.end()), dict); + auto obj_stream = CPDF_ObjectStream::Create(std::move(stream)); + ASSERT_TRUE(obj_stream); + + EXPECT_THAT(obj_stream->object_info(), + ElementsAre(CPDF_ObjectStream::ObjectInfo(10, 0), + CPDF_ObjectStream::ObjectInfo(11, 14), + CPDF_ObjectStream::ObjectInfo(12, 21))); + + // Check expected indices. + CPDF_IndirectObjectHolder holder; + RetainPtr<CPDF_Object> obj10 = obj_stream->ParseObject(&holder, 10, 0); + ASSERT_TRUE(obj10); + EXPECT_EQ(10u, obj10->GetObjNum()); + EXPECT_EQ(0u, obj10->GetGenNum()); + EXPECT_TRUE(obj10->IsDictionary()); + + RetainPtr<CPDF_Object> obj11 = obj_stream->ParseObject(&holder, 11, 1); + ASSERT_TRUE(obj11); + EXPECT_EQ(11u, obj11->GetObjNum()); + EXPECT_EQ(0u, obj11->GetGenNum()); + EXPECT_TRUE(obj11->IsArray()); + + RetainPtr<CPDF_Object> obj12 = obj_stream->ParseObject(&holder, 12, 2); + ASSERT_TRUE(obj12); + EXPECT_EQ(12u, obj12->GetObjNum()); + EXPECT_EQ(0u, obj12->GetGenNum()); + EXPECT_TRUE(obj12->IsNumber()); + + // Check bad indices. + EXPECT_FALSE(obj_stream->ParseObject(&holder, 10, 1)); + EXPECT_FALSE(obj_stream->ParseObject(&holder, 10, 2)); + EXPECT_FALSE(obj_stream->ParseObject(&holder, 10, 3)); + EXPECT_FALSE(obj_stream->ParseObject(&holder, 11, 0)); + EXPECT_FALSE(obj_stream->ParseObject(&holder, 11, 2)); + EXPECT_FALSE(obj_stream->ParseObject(&holder, 11, 3)); + EXPECT_FALSE(obj_stream->ParseObject(&holder, 12, 0)); + EXPECT_FALSE(obj_stream->ParseObject(&holder, 12, 1)); + EXPECT_FALSE(obj_stream->ParseObject(&holder, 12, 3)); +} + +TEST(ObjectStreamTest, StreamNoDict) { + ByteStringView contents_view(kNormalStreamContent); + auto stream = pdfium::MakeRetain<CPDF_Stream>( + DataVector<uint8_t>(contents_view.begin(), contents_view.end()), + /*pDict=*/nullptr); + EXPECT_FALSE(CPDF_ObjectStream::Create(std::move(stream))); +} + +TEST(ObjectStreamTest, StreamDictNoType) { + auto dict = pdfium::MakeRetain<CPDF_Dictionary>(); + dict->SetNewFor<CPDF_Number>("N", 3); + dict->SetNewFor<CPDF_Number>("First", 5); + + ByteStringView contents_view(kNormalStreamContent); + auto stream = pdfium::MakeRetain<CPDF_Stream>( + DataVector<uint8_t>(contents_view.begin(), contents_view.end()), dict); + EXPECT_FALSE(CPDF_ObjectStream::Create(std::move(stream))); +} + +TEST(ObjectStreamTest, StreamDictWrongType) { + auto dict = pdfium::MakeRetain<CPDF_Dictionary>(); + dict->SetNewFor<CPDF_String>("Type", "ObjStm", /*bHex=*/false); + dict->SetNewFor<CPDF_Number>("N", 3); + dict->SetNewFor<CPDF_Number>("First", 5); + + ByteStringView contents_view(kNormalStreamContent); + auto stream = pdfium::MakeRetain<CPDF_Stream>( + DataVector<uint8_t>(contents_view.begin(), contents_view.end()), dict); + EXPECT_FALSE(CPDF_ObjectStream::Create(std::move(stream))); +} + +TEST(ObjectStreamTest, StreamDictWrongTypeValue) { + auto dict = pdfium::MakeRetain<CPDF_Dictionary>(); + dict->SetNewFor<CPDF_Name>("Type", "ObjStmmmm"); + dict->SetNewFor<CPDF_Number>("N", 3); + dict->SetNewFor<CPDF_Number>("First", 5); + + ByteStringView contents_view(kNormalStreamContent); + auto stream = pdfium::MakeRetain<CPDF_Stream>( + DataVector<uint8_t>(contents_view.begin(), contents_view.end()), dict); + EXPECT_FALSE(CPDF_ObjectStream::Create(std::move(stream))); +} + +TEST(ObjectStreamTest, StreamDictNoCount) { + auto dict = pdfium::MakeRetain<CPDF_Dictionary>(); + dict->SetNewFor<CPDF_Name>("Type", "ObjStm"); + dict->SetNewFor<CPDF_Number>("First", 5); + + ByteStringView contents_view(kNormalStreamContent); + auto stream = pdfium::MakeRetain<CPDF_Stream>( + DataVector<uint8_t>(contents_view.begin(), contents_view.end()), dict); + EXPECT_FALSE(CPDF_ObjectStream::Create(std::move(stream))); +} + +TEST(ObjectStreamTest, StreamDictFloatCount) { + auto dict = pdfium::MakeRetain<CPDF_Dictionary>(); + dict->SetNewFor<CPDF_Name>("Type", "ObjStm"); + dict->SetNewFor<CPDF_Number>("N", 2.2f); + dict->SetNewFor<CPDF_Number>("First", 5); + + ByteStringView contents_view(kNormalStreamContent); + auto stream = pdfium::MakeRetain<CPDF_Stream>( + DataVector<uint8_t>(contents_view.begin(), contents_view.end()), dict); + EXPECT_FALSE(CPDF_ObjectStream::Create(std::move(stream))); +} + +TEST(ObjectStreamTest, StreamDictNegativeCount) { + auto dict = pdfium::MakeRetain<CPDF_Dictionary>(); + dict->SetNewFor<CPDF_Name>("Type", "ObjStm"); + dict->SetNewFor<CPDF_Number>("N", -1); + dict->SetNewFor<CPDF_Number>("First", 5); + + ByteStringView contents_view(kNormalStreamContent); + auto stream = pdfium::MakeRetain<CPDF_Stream>( + DataVector<uint8_t>(contents_view.begin(), contents_view.end()), dict); + EXPECT_FALSE(CPDF_ObjectStream::Create(std::move(stream))); +} + +TEST(ObjectStreamTest, StreamDictCountTooBig) { + auto dict = pdfium::MakeRetain<CPDF_Dictionary>(); + dict->SetNewFor<CPDF_Name>("Type", "ObjStm"); + dict->SetNewFor<CPDF_Number>("N", 999999999); + dict->SetNewFor<CPDF_Number>("First", 5); + + ByteStringView contents_view(kNormalStreamContent); + auto stream = pdfium::MakeRetain<CPDF_Stream>( + DataVector<uint8_t>(contents_view.begin(), contents_view.end()), dict); + EXPECT_FALSE(CPDF_ObjectStream::Create(std::move(stream))); +} + +TEST(ObjectStreamTest, StreamDictNoOffset) { + auto dict = pdfium::MakeRetain<CPDF_Dictionary>(); + dict->SetNewFor<CPDF_Name>("Type", "ObjStm"); + dict->SetNewFor<CPDF_Number>("N", 3); + + ByteStringView contents_view(kNormalStreamContent); + auto stream = pdfium::MakeRetain<CPDF_Stream>( + DataVector<uint8_t>(contents_view.begin(), contents_view.end()), dict); + EXPECT_FALSE(CPDF_ObjectStream::Create(std::move(stream))); +} + +TEST(ObjectStreamTest, StreamDictFloatOffset) { + auto dict = pdfium::MakeRetain<CPDF_Dictionary>(); + dict->SetNewFor<CPDF_Name>("Type", "ObjStm"); + dict->SetNewFor<CPDF_Number>("N", 3); + dict->SetNewFor<CPDF_Number>("First", 5.5f); + + ByteStringView contents_view(kNormalStreamContent); + auto stream = pdfium::MakeRetain<CPDF_Stream>( + DataVector<uint8_t>(contents_view.begin(), contents_view.end()), dict); + EXPECT_FALSE(CPDF_ObjectStream::Create(std::move(stream))); +} + +TEST(ObjectStreamTest, StreamDictNegativeOffset) { + auto dict = pdfium::MakeRetain<CPDF_Dictionary>(); + dict->SetNewFor<CPDF_Name>("Type", "ObjStm"); + dict->SetNewFor<CPDF_Number>("N", 3); + dict->SetNewFor<CPDF_Number>("First", -5); + + ByteStringView contents_view(kNormalStreamContent); + auto stream = pdfium::MakeRetain<CPDF_Stream>( + DataVector<uint8_t>(contents_view.begin(), contents_view.end()), dict); + EXPECT_FALSE(CPDF_ObjectStream::Create(std::move(stream))); +} + +TEST(ObjectStreamTest, StreamDictOffsetTooBig) { + auto dict = pdfium::MakeRetain<CPDF_Dictionary>(); + dict->SetNewFor<CPDF_Name>("Type", "ObjStm"); + dict->SetNewFor<CPDF_Number>("N", 3); + constexpr int kTooBigOffset = std::size(kNormalStreamContent); + dict->SetNewFor<CPDF_Number>("First", kTooBigOffset); + + ByteStringView contents_view(kNormalStreamContent); + auto stream = pdfium::MakeRetain<CPDF_Stream>( + DataVector<uint8_t>(contents_view.begin(), contents_view.end()), dict); + auto obj_stream = CPDF_ObjectStream::Create(std::move(stream)); + ASSERT_TRUE(obj_stream); + + EXPECT_THAT(obj_stream->object_info(), + ElementsAre(CPDF_ObjectStream::ObjectInfo(10, 0), + CPDF_ObjectStream::ObjectInfo(11, 14), + CPDF_ObjectStream::ObjectInfo(12, 21))); + + CPDF_IndirectObjectHolder holder; + EXPECT_FALSE(obj_stream->ParseObject(&holder, 10, 0)); + EXPECT_FALSE(obj_stream->ParseObject(&holder, 11, 1)); + EXPECT_FALSE(obj_stream->ParseObject(&holder, 12, 2)); +} + +TEST(ObjectStreamTest, StreamDictTooFewCount) { + auto dict = pdfium::MakeRetain<CPDF_Dictionary>(); + dict->SetNewFor<CPDF_Name>("Type", "ObjStm"); + dict->SetNewFor<CPDF_Number>("N", 2); + dict->SetNewFor<CPDF_Number>("First", kNormalStreamContentOffset); + + ByteStringView contents_view(kNormalStreamContent); + auto stream = pdfium::MakeRetain<CPDF_Stream>( + DataVector<uint8_t>(contents_view.begin(), contents_view.end()), dict); + auto obj_stream = CPDF_ObjectStream::Create(std::move(stream)); + ASSERT_TRUE(obj_stream); + + EXPECT_THAT(obj_stream->object_info(), + ElementsAre(CPDF_ObjectStream::ObjectInfo(10, 0), + CPDF_ObjectStream::ObjectInfo(11, 14))); + + CPDF_IndirectObjectHolder holder; + RetainPtr<CPDF_Object> obj10 = obj_stream->ParseObject(&holder, 10, 0); + ASSERT_TRUE(obj10); + EXPECT_EQ(10u, obj10->GetObjNum()); + EXPECT_EQ(0u, obj10->GetGenNum()); + EXPECT_TRUE(obj10->IsDictionary()); + + RetainPtr<CPDF_Object> obj11 = obj_stream->ParseObject(&holder, 11, 1); + ASSERT_TRUE(obj11); + EXPECT_EQ(11u, obj11->GetObjNum()); + EXPECT_EQ(0u, obj11->GetGenNum()); + EXPECT_TRUE(obj11->IsArray()); + + EXPECT_FALSE(obj_stream->ParseObject(&holder, 12, 2)); +} + +TEST(ObjectStreamTest, StreamDictTooManyObject) { + auto dict = pdfium::MakeRetain<CPDF_Dictionary>(); + dict->SetNewFor<CPDF_Name>("Type", "ObjStm"); + dict->SetNewFor<CPDF_Number>("N", 9); + dict->SetNewFor<CPDF_Number>("First", kNormalStreamContentOffset); + + ByteStringView contents_view(kNormalStreamContent); + auto stream = pdfium::MakeRetain<CPDF_Stream>( + DataVector<uint8_t>(contents_view.begin(), contents_view.end()), dict); + auto obj_stream = CPDF_ObjectStream::Create(std::move(stream)); + ASSERT_TRUE(obj_stream); + + // TODO(thestig): Can this avoid finding object 2? + EXPECT_THAT(obj_stream->object_info(), + ElementsAre(CPDF_ObjectStream::ObjectInfo(10, 0), + CPDF_ObjectStream::ObjectInfo(11, 14), + CPDF_ObjectStream::ObjectInfo(12, 21), + CPDF_ObjectStream::ObjectInfo(2, 3))); + + CPDF_IndirectObjectHolder holder; + EXPECT_FALSE(obj_stream->ParseObject(&holder, 2, 0)); + EXPECT_FALSE(obj_stream->ParseObject(&holder, 2, 1)); + EXPECT_FALSE(obj_stream->ParseObject(&holder, 2, 2)); + EXPECT_FALSE(obj_stream->ParseObject(&holder, 2, 3)); + EXPECT_FALSE(obj_stream->ParseObject(&holder, 2, 4)); +} + +TEST(ObjectStreamTest, StreamDictGarbageObjNum) { + auto dict = pdfium::MakeRetain<CPDF_Dictionary>(); + dict->SetNewFor<CPDF_Name>("Type", "ObjStm"); + dict->SetNewFor<CPDF_Number>("N", 3); + dict->SetNewFor<CPDF_Number>("First", 19); + + const char kStreamContent[] = "10 0 hi 14 12 21<</Name /Foo>>[1 2 3]4"; + ByteStringView contents_view(kStreamContent); + auto stream = pdfium::MakeRetain<CPDF_Stream>( + DataVector<uint8_t>(contents_view.begin(), contents_view.end()), dict); + auto obj_stream = CPDF_ObjectStream::Create(std::move(stream)); + ASSERT_TRUE(obj_stream); + + EXPECT_THAT(obj_stream->object_info(), + ElementsAre(CPDF_ObjectStream::ObjectInfo(10, 0), + CPDF_ObjectStream::ObjectInfo(12, 21))); +} + +TEST(ObjectStreamTest, StreamDictGarbageObjectOffset) { + auto dict = pdfium::MakeRetain<CPDF_Dictionary>(); + dict->SetNewFor<CPDF_Name>("Type", "ObjStm"); + dict->SetNewFor<CPDF_Number>("N", 3); + dict->SetNewFor<CPDF_Number>("First", 16); + + const char kStreamContent[] = "10 0 11 hi 12 21<</Name /Foo>>[1 2 3]4"; + ByteStringView contents_view(kStreamContent); + auto stream = pdfium::MakeRetain<CPDF_Stream>( + DataVector<uint8_t>(contents_view.begin(), contents_view.end()), dict); + auto obj_stream = CPDF_ObjectStream::Create(std::move(stream)); + ASSERT_TRUE(obj_stream); + + // TODO(thestig): Should object 11 be rejected? + EXPECT_THAT(obj_stream->object_info(), + ElementsAre(CPDF_ObjectStream::ObjectInfo(10, 0), + CPDF_ObjectStream::ObjectInfo(11, 0), + CPDF_ObjectStream::ObjectInfo(12, 21))); + + CPDF_IndirectObjectHolder holder; + RetainPtr<CPDF_Object> obj10 = obj_stream->ParseObject(&holder, 10, 0); + ASSERT_TRUE(obj10); + EXPECT_EQ(10u, obj10->GetObjNum()); + EXPECT_EQ(0u, obj10->GetGenNum()); + EXPECT_TRUE(obj10->IsDictionary()); + + RetainPtr<CPDF_Object> obj11 = obj_stream->ParseObject(&holder, 11, 1); + ASSERT_TRUE(obj11); + EXPECT_EQ(11u, obj11->GetObjNum()); + EXPECT_EQ(0u, obj11->GetGenNum()); + EXPECT_TRUE(obj11->IsDictionary()); +} + +TEST(ObjectStreamTest, StreamDictNegativeObjectOffset) { + auto dict = pdfium::MakeRetain<CPDF_Dictionary>(); + dict->SetNewFor<CPDF_Name>("Type", "ObjStm"); + dict->SetNewFor<CPDF_Number>("N", 3); + dict->SetNewFor<CPDF_Number>("First", 16); + + const char kStreamContent[] = "10 0 11 -1 12 21<</Name /Foo>>[1 2 3]4"; + ByteStringView contents_view(kStreamContent); + auto stream = pdfium::MakeRetain<CPDF_Stream>( + DataVector<uint8_t>(contents_view.begin(), contents_view.end()), dict); + auto obj_stream = CPDF_ObjectStream::Create(std::move(stream)); + ASSERT_TRUE(obj_stream); + + // TODO(thestig): Should object 11 be rejected? + EXPECT_THAT(obj_stream->object_info(), + ElementsAre(CPDF_ObjectStream::ObjectInfo(10, 0), + CPDF_ObjectStream::ObjectInfo(11, 4294967295), + CPDF_ObjectStream::ObjectInfo(12, 21))); + + CPDF_IndirectObjectHolder holder; + EXPECT_FALSE(obj_stream->ParseObject(&holder, 11, 1)); +} + +TEST(ObjectStreamTest, StreamDictObjectOffsetTooBig) { + auto dict = pdfium::MakeRetain<CPDF_Dictionary>(); + dict->SetNewFor<CPDF_Name>("Type", "ObjStm"); + dict->SetNewFor<CPDF_Number>("N", 3); + dict->SetNewFor<CPDF_Number>("First", 17); + + const char kStreamContent[] = "10 0 11 999 12 21<</Name /Foo>>[1 2 3]4"; + ByteStringView contents_view(kStreamContent); + auto stream = pdfium::MakeRetain<CPDF_Stream>( + DataVector<uint8_t>(contents_view.begin(), contents_view.end()), dict); + auto obj_stream = CPDF_ObjectStream::Create(std::move(stream)); + ASSERT_TRUE(obj_stream); + + // TODO(thestig): Should object 11 be rejected? + EXPECT_THAT(obj_stream->object_info(), + ElementsAre(CPDF_ObjectStream::ObjectInfo(10, 0), + CPDF_ObjectStream::ObjectInfo(11, 999), + CPDF_ObjectStream::ObjectInfo(12, 21))); + + CPDF_IndirectObjectHolder holder; + EXPECT_FALSE(obj_stream->ParseObject(&holder, 11, 1)); +} + +TEST(ObjectStreamTest, StreamDictDuplicateObjNum) { + auto dict = pdfium::MakeRetain<CPDF_Dictionary>(); + dict->SetNewFor<CPDF_Name>("Type", "ObjStm"); + dict->SetNewFor<CPDF_Number>("N", 3); + dict->SetNewFor<CPDF_Number>("First", 16); + + const char kStreamContent[] = "10 0 10 14 12 21<</Name /Foo>>[1 2 3]4"; + ByteStringView contents_view(kStreamContent); + auto stream = pdfium::MakeRetain<CPDF_Stream>( + DataVector<uint8_t>(contents_view.begin(), contents_view.end()), dict); + auto obj_stream = CPDF_ObjectStream::Create(std::move(stream)); + ASSERT_TRUE(obj_stream); + + EXPECT_THAT(obj_stream->object_info(), + ElementsAre(CPDF_ObjectStream::ObjectInfo(10, 0), + CPDF_ObjectStream::ObjectInfo(10, 14), + CPDF_ObjectStream::ObjectInfo(12, 21))); + + CPDF_IndirectObjectHolder holder; + RetainPtr<CPDF_Object> obj10 = obj_stream->ParseObject(&holder, 10, 0); + ASSERT_TRUE(obj10); + EXPECT_EQ(10u, obj10->GetObjNum()); + EXPECT_EQ(0u, obj10->GetGenNum()); + EXPECT_TRUE(obj10->IsDictionary()); + + obj10 = obj_stream->ParseObject(&holder, 10, 1); + ASSERT_TRUE(obj10); + EXPECT_EQ(10u, obj10->GetObjNum()); + EXPECT_EQ(0u, obj10->GetGenNum()); + EXPECT_TRUE(obj10->IsArray()); + + EXPECT_FALSE(obj_stream->ParseObject(&holder, 10, 2)); + EXPECT_FALSE(obj_stream->ParseObject(&holder, 10, 3)); + + RetainPtr<CPDF_Object> obj12 = obj_stream->ParseObject(&holder, 12, 2); + ASSERT_TRUE(obj12); + EXPECT_EQ(12u, obj12->GetObjNum()); + EXPECT_EQ(0u, obj12->GetGenNum()); + EXPECT_TRUE(obj12->IsNumber()); +} + +TEST(ObjectStreamTest, StreamDictUnorderedObjectNumbers) { + // ISO 32000-1:2008 spec. section 7.5.7, note 6 says there is no restriction + // on object number ordering. + auto dict = pdfium::MakeRetain<CPDF_Dictionary>(); + dict->SetNewFor<CPDF_Name>("Type", "ObjStm"); + dict->SetNewFor<CPDF_Number>("N", 3); + dict->SetNewFor<CPDF_Number>("First", 16); + + const char kStreamContent[] = "11 0 12 14 10 21<</Name /Foo>>[1 2 3]4"; + ByteStringView contents_view(kStreamContent); + auto stream = pdfium::MakeRetain<CPDF_Stream>( + DataVector<uint8_t>(contents_view.begin(), contents_view.end()), dict); + auto obj_stream = CPDF_ObjectStream::Create(std::move(stream)); + ASSERT_TRUE(obj_stream); + + EXPECT_THAT(obj_stream->object_info(), + ElementsAre(CPDF_ObjectStream::ObjectInfo(11, 0), + CPDF_ObjectStream::ObjectInfo(12, 14), + CPDF_ObjectStream::ObjectInfo(10, 21))); + + CPDF_IndirectObjectHolder holder; + RetainPtr<CPDF_Object> obj10 = obj_stream->ParseObject(&holder, 10, 2); + ASSERT_TRUE(obj10); + EXPECT_EQ(10u, obj10->GetObjNum()); + EXPECT_EQ(0u, obj10->GetGenNum()); + EXPECT_TRUE(obj10->IsNumber()); + + RetainPtr<CPDF_Object> obj11 = obj_stream->ParseObject(&holder, 11, 0); + ASSERT_TRUE(obj11); + EXPECT_EQ(11u, obj11->GetObjNum()); + EXPECT_EQ(0u, obj11->GetGenNum()); + EXPECT_TRUE(obj11->IsDictionary()); + + RetainPtr<CPDF_Object> obj12 = obj_stream->ParseObject(&holder, 12, 1); + ASSERT_TRUE(obj12); + EXPECT_EQ(12u, obj12->GetObjNum()); + EXPECT_EQ(0u, obj12->GetGenNum()); + EXPECT_TRUE(obj12->IsArray()); +} + +TEST(ObjectStreamTest, StreamDictUnorderedObjectOffsets) { + // ISO 32000-1:2008 spec. section 7.5.7, says offsets shall be in increasing + // order. + // TODO(thestig): Should CPDF_ObjectStream check for this and reject this + // object stream? + auto dict = pdfium::MakeRetain<CPDF_Dictionary>(); + dict->SetNewFor<CPDF_Name>("Type", "ObjStm"); + dict->SetNewFor<CPDF_Number>("N", 3); + dict->SetNewFor<CPDF_Number>("First", 16); + + const char kStreamContent[] = "10 21 11 0 12 14<</Name /Foo>>[1 2 3]4"; + ByteStringView contents_view(kStreamContent); + auto stream = pdfium::MakeRetain<CPDF_Stream>( + DataVector<uint8_t>(contents_view.begin(), contents_view.end()), dict); + auto obj_stream = CPDF_ObjectStream::Create(std::move(stream)); + ASSERT_TRUE(obj_stream); + + EXPECT_THAT(obj_stream->object_info(), + ElementsAre(CPDF_ObjectStream::ObjectInfo(10, 21), + CPDF_ObjectStream::ObjectInfo(11, 0), + CPDF_ObjectStream::ObjectInfo(12, 14))); + + CPDF_IndirectObjectHolder holder; + RetainPtr<CPDF_Object> obj10 = obj_stream->ParseObject(&holder, 10, 0); + ASSERT_TRUE(obj10); + EXPECT_EQ(10u, obj10->GetObjNum()); + EXPECT_EQ(0u, obj10->GetGenNum()); + EXPECT_TRUE(obj10->IsNumber()); + + RetainPtr<CPDF_Object> obj11 = obj_stream->ParseObject(&holder, 11, 1); + ASSERT_TRUE(obj11); + EXPECT_EQ(11u, obj11->GetObjNum()); + EXPECT_EQ(0u, obj11->GetGenNum()); + EXPECT_TRUE(obj11->IsDictionary()); + + RetainPtr<CPDF_Object> obj12 = obj_stream->ParseObject(&holder, 12, 2); + ASSERT_TRUE(obj12); + EXPECT_EQ(12u, obj12->GetObjNum()); + EXPECT_EQ(0u, obj12->GetGenNum()); + EXPECT_TRUE(obj12->IsArray()); +}
diff --git a/core/fpdfapi/parser/cpdf_object_unittest.cpp b/core/fpdfapi/parser/cpdf_object_unittest.cpp index ca02618..a57b85e 100644 --- a/core/fpdfapi/parser/cpdf_object_unittest.cpp +++ b/core/fpdfapi/parser/cpdf_object_unittest.cpp
@@ -1,7 +1,11 @@ -// Copyright 2016 PDFium Authors. All rights reserved. +// Copyright 2016 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include "core/fpdfapi/parser/cpdf_object.h" + +#include <stdint.h> + #include <memory> #include <string> #include <utility> @@ -19,9 +23,9 @@ #include "core/fpdfapi/parser/cpdf_stream.h" #include "core/fpdfapi/parser/cpdf_stream_acc.h" #include "core/fpdfapi/parser/cpdf_string.h" +#include "core/fxcrt/data_vector.h" #include "core/fxcrt/fx_memory_wrappers.h" #include "testing/gtest/include/gtest/gtest.h" -#include "third_party/base/ptr_util.h" namespace { @@ -34,9 +38,9 @@ CPDF_Array* arr_val, CPDF_Dictionary* dict_val, CPDF_Stream* stream_val) { - EXPECT_STREQ(str_val, arr->GetStringAt(index).c_str()); + EXPECT_STREQ(str_val, arr->GetByteStringAt(index).c_str()); EXPECT_EQ(int_val, arr->GetIntegerAt(index)); - EXPECT_EQ(float_val, arr->GetNumberAt(index)); + EXPECT_EQ(float_val, arr->GetFloatAt(index)); EXPECT_EQ(arr_val, arr->GetArrayAt(index)); EXPECT_EQ(dict_val, arr->GetDictAt(index)); EXPECT_EQ(stream_val, arr->GetStreamAt(index)); @@ -69,16 +73,14 @@ m_DictObj->SetNewFor<CPDF_Boolean>("bool", false); m_DictObj->SetNewFor<CPDF_Number>("num", 0.23f); // Stream object. - const char content[] = "abcdefghijklmnopqrstuvwxyz"; - size_t buf_len = FX_ArraySize(content); - std::unique_ptr<uint8_t, FxFreeDeleter> buf(FX_Alloc(uint8_t, buf_len)); - memcpy(buf.get(), content, buf_len); + static constexpr char kContents[] = "abcdefghijklmnopqrstuvwxyz"; auto pNewDict = pdfium::MakeRetain<CPDF_Dictionary>(); m_StreamDictObj = pNewDict; m_StreamDictObj->SetNewFor<CPDF_String>("key1", L" test dict"); m_StreamDictObj->SetNewFor<CPDF_Number>("key2", -1); - auto stream_obj = pdfium::MakeRetain<CPDF_Stream>(std::move(buf), buf_len, - std::move(pNewDict)); + auto stream_obj = pdfium::MakeRetain<CPDF_Stream>( + DataVector<uint8_t>(std::begin(kContents), std::end(kContents)), + std::move(pNewDict)); // Null Object. auto null_obj = pdfium::MakeRetain<CPDF_Null>(); // All direct objects. @@ -92,21 +94,22 @@ CPDF_Object::kNumber, CPDF_Object::kString, CPDF_Object::kString, CPDF_Object::kName, CPDF_Object::kArray, CPDF_Object::kDictionary, CPDF_Object::kStream, CPDF_Object::kNullobj}; - for (size_t i = 0; i < FX_ArraySize(objs); ++i) + for (size_t i = 0; i < std::size(objs); ++i) m_DirectObjs.emplace_back(objs[i]); // Indirect references to indirect objects. - m_ObjHolder = pdfium::MakeUnique<CPDF_IndirectObjectHolder>(); - m_IndirectObjs = {m_ObjHolder->AddIndirectObject(boolean_true_obj->Clone()), - m_ObjHolder->AddIndirectObject(number_int_obj->Clone()), - m_ObjHolder->AddIndirectObject(str_spec_obj->Clone()), - m_ObjHolder->AddIndirectObject(name_obj->Clone()), - m_ObjHolder->AddIndirectObject(m_ArrayObj->Clone()), - m_ObjHolder->AddIndirectObject(m_DictObj->Clone()), - m_ObjHolder->AddIndirectObject(stream_obj->Clone())}; - for (CPDF_Object* pObj : m_IndirectObjs) { - m_RefObjs.emplace_back(pdfium::MakeRetain<CPDF_Reference>( - m_ObjHolder.get(), pObj->GetObjNum())); + m_ObjHolder = std::make_unique<CPDF_IndirectObjectHolder>(); + m_IndirectObjNums = { + m_ObjHolder->AddIndirectObject(boolean_true_obj->Clone()), + m_ObjHolder->AddIndirectObject(number_int_obj->Clone()), + m_ObjHolder->AddIndirectObject(str_spec_obj->Clone()), + m_ObjHolder->AddIndirectObject(name_obj->Clone()), + m_ObjHolder->AddIndirectObject(m_ArrayObj->Clone()), + m_ObjHolder->AddIndirectObject(m_DictObj->Clone()), + m_ObjHolder->AddIndirectObject(stream_obj->Clone())}; + for (uint32_t objnum : m_IndirectObjNums) { + m_RefObjs.emplace_back( + pdfium::MakeRetain<CPDF_Reference>(m_ObjHolder.get(), objnum)); } } @@ -130,8 +133,10 @@ if (array1->size() != array2->size()) return false; for (size_t i = 0; i < array1->size(); ++i) { - if (!Equal(array1->GetObjectAt(i), array2->GetObjectAt(i))) + if (!Equal(array1->GetObjectAt(i).Get(), + array2->GetObjectAt(i).Get())) { return false; + } } return true; } @@ -142,7 +147,7 @@ return false; CPDF_DictionaryLocker locker1(dict1); for (const auto& item : locker1) { - if (!Equal(item.second.Get(), dict2->GetObjectFor(item.first))) + if (!Equal(item.second.Get(), dict2->GetObjectFor(item.first).Get())) return false; } return true; @@ -150,25 +155,28 @@ case CPDF_Object::kNullobj: return true; case CPDF_Object::kStream: { - const CPDF_Stream* stream1 = obj1->AsStream(); - const CPDF_Stream* stream2 = obj2->AsStream(); + RetainPtr<const CPDF_Stream> stream1(obj1->AsStream()); + RetainPtr<const CPDF_Stream> stream2(obj2->AsStream()); if (!stream1->GetDict() && !stream2->GetDict()) return true; // Compare dictionaries. - if (!Equal(stream1->GetDict(), stream2->GetDict())) + if (!Equal(stream1->GetDict().Get(), stream2->GetDict().Get())) return false; - auto streamAcc1 = pdfium::MakeRetain<CPDF_StreamAcc>(stream1); + auto streamAcc1 = + pdfium::MakeRetain<CPDF_StreamAcc>(std::move(stream1)); streamAcc1->LoadAllDataRaw(); - auto streamAcc2 = pdfium::MakeRetain<CPDF_StreamAcc>(stream2); + auto streamAcc2 = + pdfium::MakeRetain<CPDF_StreamAcc>(std::move(stream2)); streamAcc2->LoadAllDataRaw(); + pdfium::span<const uint8_t> span1 = streamAcc1->GetSpan(); + pdfium::span<const uint8_t> span2 = streamAcc2->GetSpan(); // Compare sizes. - if (streamAcc1->GetSize() != streamAcc2->GetSize()) + if (span1.size() != span2.size()) return false; - return memcmp(streamAcc1->GetData(), streamAcc2->GetData(), - streamAcc2->GetSize()) == 0; + return memcmp(span1.data(), span2.data(), span2.size()) == 0; } case CPDF_Object::kReference: return obj1->AsReference()->GetRefObjNum() == @@ -187,7 +195,7 @@ RetainPtr<CPDF_Dictionary> m_DictObj; RetainPtr<CPDF_Dictionary> m_StreamDictObj; RetainPtr<CPDF_Array> m_ArrayObj; - std::vector<CPDF_Object*> m_IndirectObjs; + std::vector<uint32_t> m_IndirectObjNums; }; TEST_F(PDFObjectsTest, GetString) { @@ -265,7 +273,24 @@ m_DictObj.Get(), m_StreamDictObj.Get()}; for (size_t i = 0; i < m_RefObjs.size(); ++i) - EXPECT_TRUE(Equal(indirect_obj_results[i], m_RefObjs[i]->GetDict())); + EXPECT_TRUE(Equal(indirect_obj_results[i], m_RefObjs[i]->GetDict().Get())); +} + +TEST_F(PDFObjectsTest, GetNameFor) { + m_DictObj->SetNewFor<CPDF_String>("string", "ium", false); + m_DictObj->SetNewFor<CPDF_Name>("name", "Pdf"); + + EXPECT_STREQ("", m_DictObj->GetNameFor("invalid").c_str()); + EXPECT_STREQ("", m_DictObj->GetNameFor("bool").c_str()); + EXPECT_STREQ("", m_DictObj->GetNameFor("num").c_str()); + EXPECT_STREQ("", m_DictObj->GetNameFor("string").c_str()); + EXPECT_STREQ("Pdf", m_DictObj->GetNameFor("name").c_str()); + + EXPECT_STREQ("", m_DictObj->GetByteStringFor("invalid").c_str()); + EXPECT_STREQ("false", m_DictObj->GetByteStringFor("bool").c_str()); + EXPECT_STREQ("0.23", m_DictObj->GetByteStringFor("num").c_str()); + EXPECT_STREQ("ium", m_DictObj->GetByteStringFor("string").c_str()); + EXPECT_STREQ("Pdf", m_DictObj->GetByteStringFor("name").c_str()); } TEST_F(PDFObjectsTest, GetArray) { @@ -278,7 +303,7 @@ // Check indirect references. for (const auto& it : m_RefObjs) - EXPECT_EQ(nullptr, it->AsArray()); + EXPECT_FALSE(it->AsArray()); } TEST_F(PDFObjectsTest, Clone) { @@ -312,7 +337,7 @@ // Check indirect references. for (size_t i = 0; i < m_RefObjs.size(); ++i) - EXPECT_EQ(m_IndirectObjs[i], m_RefObjs[i]->GetDirect()); + EXPECT_EQ(m_IndirectObjNums[i], m_RefObjs[i]->GetDirect()->GetObjNum()); } TEST_F(PDFObjectsTest, SetString) { @@ -321,7 +346,7 @@ "changed", "", "NewName"}; const char* const expected[] = {"true", "false", "3.125", "97", "changed", "", "NewName"}; - for (size_t i = 0; i < FX_ArraySize(set_values); ++i) { + for (size_t i = 0; i < std::size(set_values); ++i) { m_DirectObjs[i]->SetString(set_values[i]); EXPECT_STREQ(expected[i], m_DirectObjs[i]->GetString().c_str()); } @@ -335,7 +360,7 @@ EXPECT_EQ(m_DirectObjs[i].Get(), m_DirectObjs[i]->AsArray()); } else { EXPECT_FALSE(m_DirectObjs[i]->IsArray()); - EXPECT_EQ(nullptr, m_DirectObjs[i]->AsArray()); + EXPECT_FALSE(m_DirectObjs[i]->AsArray()); } if (m_DirectObjTypes[i] == CPDF_Object::kBoolean) { @@ -343,7 +368,7 @@ EXPECT_EQ(m_DirectObjs[i].Get(), m_DirectObjs[i]->AsBoolean()); } else { EXPECT_FALSE(m_DirectObjs[i]->IsBoolean()); - EXPECT_EQ(nullptr, m_DirectObjs[i]->AsBoolean()); + EXPECT_FALSE(m_DirectObjs[i]->AsBoolean()); } if (m_DirectObjTypes[i] == CPDF_Object::kName) { @@ -351,7 +376,7 @@ EXPECT_EQ(m_DirectObjs[i].Get(), m_DirectObjs[i]->AsName()); } else { EXPECT_FALSE(m_DirectObjs[i]->IsName()); - EXPECT_EQ(nullptr, m_DirectObjs[i]->AsName()); + EXPECT_FALSE(m_DirectObjs[i]->AsName()); } if (m_DirectObjTypes[i] == CPDF_Object::kNumber) { @@ -359,7 +384,7 @@ EXPECT_EQ(m_DirectObjs[i].Get(), m_DirectObjs[i]->AsNumber()); } else { EXPECT_FALSE(m_DirectObjs[i]->IsNumber()); - EXPECT_EQ(nullptr, m_DirectObjs[i]->AsNumber()); + EXPECT_FALSE(m_DirectObjs[i]->AsNumber()); } if (m_DirectObjTypes[i] == CPDF_Object::kString) { @@ -367,7 +392,7 @@ EXPECT_EQ(m_DirectObjs[i].Get(), m_DirectObjs[i]->AsString()); } else { EXPECT_FALSE(m_DirectObjs[i]->IsString()); - EXPECT_EQ(nullptr, m_DirectObjs[i]->AsString()); + EXPECT_FALSE(m_DirectObjs[i]->AsString()); } if (m_DirectObjTypes[i] == CPDF_Object::kDictionary) { @@ -375,7 +400,7 @@ EXPECT_EQ(m_DirectObjs[i].Get(), m_DirectObjs[i]->AsDictionary()); } else { EXPECT_FALSE(m_DirectObjs[i]->IsDictionary()); - EXPECT_EQ(nullptr, m_DirectObjs[i]->AsDictionary()); + EXPECT_FALSE(m_DirectObjs[i]->AsDictionary()); } if (m_DirectObjTypes[i] == CPDF_Object::kStream) { @@ -383,11 +408,11 @@ EXPECT_EQ(m_DirectObjs[i].Get(), m_DirectObjs[i]->AsStream()); } else { EXPECT_FALSE(m_DirectObjs[i]->IsStream()); - EXPECT_EQ(nullptr, m_DirectObjs[i]->AsStream()); + EXPECT_FALSE(m_DirectObjs[i]->AsStream()); } EXPECT_FALSE(m_DirectObjs[i]->IsReference()); - EXPECT_EQ(nullptr, m_DirectObjs[i]->AsReference()); + EXPECT_FALSE(m_DirectObjs[i]->AsReference()); } // Check indirect references. for (size_t i = 0; i < m_RefObjs.size(); ++i) { @@ -408,17 +433,33 @@ ToReference(ref_obj.Get())->GetRefObjNum()); } +TEST_F(PDFObjectsTest, KeyForCache) { + std::set<uint64_t> key_set; + + // Check all direct objects inserted without collision. + for (const auto& direct : m_DirectObjs) { + EXPECT_TRUE(key_set.insert(direct->KeyForCache()).second); + } + // Check indirect objects inserted without collision. + for (const auto& pair : *m_ObjHolder) { + EXPECT_TRUE(key_set.insert(pair.second->KeyForCache()).second); + } + + // Check all expected objects counted. + EXPECT_EQ(18u, key_set.size()); +} + TEST(PDFArrayTest, GetMatrix) { float elems[][6] = {{0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}, {1, 2, 3, 4, 5, 6}, {2.3f, 4.05f, 3, -2, -3, 0.0f}, {0.05f, 0.1f, 0.56f, 0.67f, 1.34f, 99.9f}}; - for (size_t i = 0; i < FX_ArraySize(elems); ++i) { + for (size_t i = 0; i < std::size(elems); ++i) { auto arr = pdfium::MakeRetain<CPDF_Array>(); CFX_Matrix matrix(elems[i][0], elems[i][1], elems[i][2], elems[i][3], elems[i][4], elems[i][5]); for (size_t j = 0; j < 6; ++j) - arr->AddNew<CPDF_Number>(elems[i][j]); + arr->AppendNew<CPDF_Number>(elems[i][j]); CFX_Matrix arr_matrix = arr->GetMatrix(); EXPECT_EQ(matrix.a, arr_matrix.a); EXPECT_EQ(matrix.b, arr_matrix.b); @@ -434,11 +475,11 @@ {1, 2, 5, 6}, {2.3f, 4.05f, -3, 0.0f}, {0.05f, 0.1f, 1.34f, 99.9f}}; - for (size_t i = 0; i < FX_ArraySize(elems); ++i) { + for (size_t i = 0; i < std::size(elems); ++i) { auto arr = pdfium::MakeRetain<CPDF_Array>(); - CFX_FloatRect rect(elems[i]); + CFX_FloatRect rect(elems[i][0], elems[i][1], elems[i][2], elems[i][3]); for (size_t j = 0; j < 4; ++j) - arr->AddNew<CPDF_Number>(elems[i][j]); + arr->AppendNew<CPDF_Number>(elems[i][j]); CFX_FloatRect arr_rect = arr->GetRect(); EXPECT_EQ(rect.left, arr_rect.left); EXPECT_EQ(rect.right, arr_rect.right); @@ -452,9 +493,9 @@ // Boolean array. const bool vals[] = {true, false, false, true, true}; auto arr = pdfium::MakeRetain<CPDF_Array>(); - for (size_t i = 0; i < FX_ArraySize(vals); ++i) + for (size_t i = 0; i < std::size(vals); ++i) arr->InsertNewAt<CPDF_Boolean>(i, vals[i]); - for (size_t i = 0; i < FX_ArraySize(vals); ++i) { + for (size_t i = 0; i < std::size(vals); ++i) { TestArrayAccessors(arr.Get(), i, // Array and index. vals[i] ? "true" : "false", // String value. nullptr, // Const string value. @@ -469,9 +510,9 @@ // Integer array. const int vals[] = {10, 0, -345, 2089345456, -1000000000, 567, 93658767}; auto arr = pdfium::MakeRetain<CPDF_Array>(); - for (size_t i = 0; i < FX_ArraySize(vals); ++i) + for (size_t i = 0; i < std::size(vals); ++i) arr->InsertNewAt<CPDF_Number>(i, vals[i]); - for (size_t i = 0; i < FX_ArraySize(vals); ++i) { + for (size_t i = 0; i < std::size(vals); ++i) { char buf[33]; TestArrayAccessors(arr.Get(), i, // Array and index. FXSYS_itoa(vals[i], buf, 10), // String value. @@ -490,9 +531,9 @@ const char* const expected_str[] = { "0", "0", "10", "10", "0.0345", "897.34", "-2.5", "-1", "-345", "0"}; auto arr = pdfium::MakeRetain<CPDF_Array>(); - for (size_t i = 0; i < FX_ArraySize(vals); ++i) + for (size_t i = 0; i < std::size(vals); ++i) arr->InsertNewAt<CPDF_Number>(i, vals[i]); - for (size_t i = 0; i < FX_ArraySize(vals); ++i) { + for (size_t i = 0; i < std::size(vals); ++i) { TestArrayAccessors(arr.Get(), i, // Array and index. expected_str[i], // String value. nullptr, // Const string value. @@ -509,11 +550,11 @@ ".", "EYREW", "It is a joke :)"}; auto string_array = pdfium::MakeRetain<CPDF_Array>(); auto name_array = pdfium::MakeRetain<CPDF_Array>(); - for (size_t i = 0; i < FX_ArraySize(vals); ++i) { + for (size_t i = 0; i < std::size(vals); ++i) { string_array->InsertNewAt<CPDF_String>(i, vals[i], false); name_array->InsertNewAt<CPDF_Name>(i, vals[i]); } - for (size_t i = 0; i < FX_ArraySize(vals); ++i) { + for (size_t i = 0; i < std::size(vals); ++i) { TestArrayAccessors(string_array.Get(), i, // Array and index. vals[i], // String value. vals[i], // Const string value. @@ -550,32 +591,32 @@ } { // Array of array. - CPDF_Array* vals[3]; + RetainPtr<CPDF_Array> vals[3]; auto arr = pdfium::MakeRetain<CPDF_Array>(); for (size_t i = 0; i < 3; ++i) { - vals[i] = arr->AddNew<CPDF_Array>(); + vals[i] = arr->AppendNew<CPDF_Array>(); for (size_t j = 0; j < 3; ++j) { int value = j + 100; - vals[i]->InsertNewAt<CPDF_Number>(i, value); + vals[i]->InsertNewAt<CPDF_Number>(j, value); } } for (size_t i = 0; i < 3; ++i) { - TestArrayAccessors(arr.Get(), i, // Array and index. - "", // String value. - nullptr, // Const string value. - 0, // Integer value. - 0, // Float value. - vals[i], // Array value. - nullptr, // Dictionary value. - nullptr); // Stream value. + TestArrayAccessors(arr.Get(), i, // Array and index. + "", // String value. + nullptr, // Const string value. + 0, // Integer value. + 0, // Float value. + vals[i].Get(), // Array value. + nullptr, // Dictionary value. + nullptr); // Stream value. } } { // Dictionary array. - CPDF_Dictionary* vals[3]; + RetainPtr<CPDF_Dictionary> vals[3]; auto arr = pdfium::MakeRetain<CPDF_Array>(); for (size_t i = 0; i < 3; ++i) { - vals[i] = arr->AddNew<CPDF_Dictionary>(); + vals[i] = arr->AppendNew<CPDF_Dictionary>(); for (size_t j = 0; j < 3; ++j) { std::string key("key"); char buf[33]; @@ -585,20 +626,20 @@ } } for (size_t i = 0; i < 3; ++i) { - TestArrayAccessors(arr.Get(), i, // Array and index. - "", // String value. - nullptr, // Const string value. - 0, // Integer value. - 0, // Float value. - nullptr, // Array value. - vals[i], // Dictionary value. - nullptr); // Stream value. + TestArrayAccessors(arr.Get(), i, // Array and index. + "", // String value. + nullptr, // Const string value. + 0, // Integer value. + 0, // Float value. + nullptr, // Array value. + vals[i].Get(), // Dictionary value. + nullptr); // Stream value. } } { // Stream array. RetainPtr<CPDF_Dictionary> vals[3]; - CPDF_Stream* stream_vals[3]; + RetainPtr<CPDF_Stream> stream_vals[3]; auto arr = pdfium::MakeRetain<CPDF_Array>(); for (size_t i = 0; i < 3; ++i) { vals[i] = pdfium::MakeRetain<CPDF_Dictionary>(); @@ -609,23 +650,20 @@ int value = j + 200; vals[i]->SetNewFor<CPDF_Number>(key.c_str(), value); } - uint8_t content[] = "content: this is a stream"; - size_t data_size = FX_ArraySize(content); - std::unique_ptr<uint8_t, FxFreeDeleter> data( - FX_Alloc(uint8_t, data_size)); - memcpy(data.get(), content, data_size); - stream_vals[i] = - arr->AddNew<CPDF_Stream>(std::move(data), data_size, vals[i]); + static constexpr uint8_t kContents[] = "content: this is a stream"; + stream_vals[i] = arr->AppendNew<CPDF_Stream>( + DataVector<uint8_t>(std::begin(kContents), std::end(kContents)), + vals[i]); } for (size_t i = 0; i < 3; ++i) { - TestArrayAccessors(arr.Get(), i, // Array and index. - "", // String value. - nullptr, // Const string value. - 0, // Integer value. - 0, // Float value. - nullptr, // Array value. - vals[i].Get(), // Dictionary value. - stream_vals[i]); // Stream value. + TestArrayAccessors(arr.Get(), i, // Array and index. + "", // String value. + nullptr, // Const string value. + 0, // Integer value. + 0, // Float value. + nullptr, // Array value. + vals[i].Get(), // Dictionary value. + stream_vals[i].Get()); // Stream value. } } { @@ -643,25 +681,23 @@ arr->InsertNewAt<CPDF_Name>(9, "test"); arr->InsertNewAt<CPDF_Null>(10); - CPDF_Array* arr_val = arr->InsertNewAt<CPDF_Array>(11); - arr_val->AddNew<CPDF_Number>(1); - arr_val->AddNew<CPDF_Number>(2); + auto arr_val = arr->InsertNewAt<CPDF_Array>(11); + arr_val->AppendNew<CPDF_Number>(1); + arr_val->AppendNew<CPDF_Number>(2); - CPDF_Dictionary* dict_val = arr->InsertNewAt<CPDF_Dictionary>(12); + auto dict_val = arr->InsertNewAt<CPDF_Dictionary>(12); dict_val->SetNewFor<CPDF_String>("key1", "Linda", false); dict_val->SetNewFor<CPDF_String>("key2", "Zoe", false); auto stream_dict = pdfium::MakeRetain<CPDF_Dictionary>(); stream_dict->SetNewFor<CPDF_String>("key1", "John", false); stream_dict->SetNewFor<CPDF_String>("key2", "King", false); - uint8_t data[] = "A stream for test"; + static constexpr uint8_t kData[] = "A stream for test"; // The data buffer will be owned by stream object, so it needs to be // dynamically allocated. - size_t buf_size = sizeof(data); - std::unique_ptr<uint8_t, FxFreeDeleter> buf(FX_Alloc(uint8_t, buf_size)); - memcpy(buf.get(), data, buf_size); CPDF_Stream* stream_val = arr->InsertNewAt<CPDF_Stream>( - 13, std::move(buf), buf_size, stream_dict); + 13, DataVector<uint8_t>(std::begin(kData), std::end(kData)), + stream_dict); const char* const expected_str[] = { "true", "false", "0", "-1234", "2345", "0.05", "", "It is a test!", "NAME", "test", "", "", "", ""}; @@ -670,22 +706,22 @@ const float expected_float[] = {0, 0, 0, -1234, 2345, 0.05f, 0, 0, 0, 0, 0, 0, 0, 0}; for (size_t i = 0; i < arr->size(); ++i) { - EXPECT_STREQ(expected_str[i], arr->GetStringAt(i).c_str()); + EXPECT_STREQ(expected_str[i], arr->GetByteStringAt(i).c_str()); EXPECT_EQ(expected_int[i], arr->GetIntegerAt(i)); - EXPECT_EQ(expected_float[i], arr->GetNumberAt(i)); + EXPECT_EQ(expected_float[i], arr->GetFloatAt(i)); if (i == 11) EXPECT_EQ(arr_val, arr->GetArrayAt(i)); else - EXPECT_EQ(nullptr, arr->GetArrayAt(i)); + EXPECT_FALSE(arr->GetArrayAt(i)); if (i == 13) { EXPECT_EQ(stream_dict, arr->GetDictAt(i)); EXPECT_EQ(stream_val, arr->GetStreamAt(i)); } else { - EXPECT_EQ(nullptr, arr->GetStreamAt(i)); + EXPECT_FALSE(arr->GetStreamAt(i)); if (i == 12) EXPECT_EQ(dict_val, arr->GetDictAt(i)); else - EXPECT_EQ(nullptr, arr->GetDictAt(i)); + EXPECT_FALSE(arr->GetDictAt(i)); } } } @@ -695,9 +731,9 @@ float vals[] = {1.0f, -1.0f, 0, 0.456734f, 12345.54321f, 0.5f, 1000, 0.000045f}; auto arr = pdfium::MakeRetain<CPDF_Array>(); - for (size_t i = 0; i < FX_ArraySize(vals); ++i) - arr->AddNew<CPDF_Number>(vals[i]); - for (size_t i = 0; i < FX_ArraySize(vals); ++i) { + for (size_t i = 0; i < std::size(vals); ++i) + arr->AppendNew<CPDF_Number>(vals[i]); + for (size_t i = 0; i < std::size(vals); ++i) { EXPECT_EQ(CPDF_Object::kNumber, arr->GetObjectAt(i)->GetType()); EXPECT_EQ(vals[i], arr->GetObjectAt(i)->GetNumber()); } @@ -706,9 +742,9 @@ TEST(PDFArrayTest, AddInteger) { int vals[] = {0, 1, 934435456, 876, 10000, -1, -24354656, -100}; auto arr = pdfium::MakeRetain<CPDF_Array>(); - for (size_t i = 0; i < FX_ArraySize(vals); ++i) - arr->AddNew<CPDF_Number>(vals[i]); - for (size_t i = 0; i < FX_ArraySize(vals); ++i) { + for (size_t i = 0; i < std::size(vals); ++i) + arr->AppendNew<CPDF_Number>(vals[i]); + for (size_t i = 0; i < std::size(vals); ++i) { EXPECT_EQ(CPDF_Object::kNumber, arr->GetObjectAt(i)->GetType()); EXPECT_EQ(vals[i], arr->GetObjectAt(i)->GetNumber()); } @@ -721,10 +757,10 @@ auto string_array = pdfium::MakeRetain<CPDF_Array>(); auto name_array = pdfium::MakeRetain<CPDF_Array>(); for (const char* val : kVals) { - string_array->AddNew<CPDF_String>(val, false); - name_array->AddNew<CPDF_Name>(val); + string_array->AppendNew<CPDF_String>(val, false); + name_array->AppendNew<CPDF_Name>(val); } - for (size_t i = 0; i < FX_ArraySize(kVals); ++i) { + for (size_t i = 0; i < std::size(kVals); ++i) { EXPECT_EQ(CPDF_Object::kString, string_array->GetObjectAt(i)->GetType()); EXPECT_STREQ(kVals[i], string_array->GetObjectAt(i)->GetString().c_str()); EXPECT_EQ(CPDF_Object::kName, name_array->GetObjectAt(i)->GetType()); @@ -733,7 +769,7 @@ } TEST(PDFArrayTest, AddReferenceAndGetObjectAt) { - auto holder = pdfium::MakeUnique<CPDF_IndirectObjectHolder>(); + auto holder = std::make_unique<CPDF_IndirectObjectHolder>(); auto boolean_obj = pdfium::MakeRetain<CPDF_Boolean>(true); auto int_obj = pdfium::MakeRetain<CPDF_Number>(-1234); auto float_obj = pdfium::MakeRetain<CPDF_Number>(2345.089f); @@ -747,14 +783,15 @@ auto arr = pdfium::MakeRetain<CPDF_Array>(); auto arr1 = pdfium::MakeRetain<CPDF_Array>(); // Create two arrays of references by different AddReference() APIs. - for (size_t i = 0; i < FX_ArraySize(indirect_objs); ++i) { + for (size_t i = 0; i < std::size(indirect_objs); ++i) { holder->ReplaceIndirectObjectIfHigherGeneration(obj_nums[i], indirect_objs[i]); - arr->AddNew<CPDF_Reference>(holder.get(), obj_nums[i]); - arr1->AddNew<CPDF_Reference>(holder.get(), indirect_objs[i]->GetObjNum()); + arr->AppendNew<CPDF_Reference>(holder.get(), obj_nums[i]); + arr1->AppendNew<CPDF_Reference>(holder.get(), + indirect_objs[i]->GetObjNum()); } // Check indirect objects. - for (size_t i = 0; i < FX_ArraySize(obj_nums); ++i) + for (size_t i = 0; i < std::size(obj_nums); ++i) EXPECT_EQ(indirect_objs[i], holder->GetOrParseIndirectObject(obj_nums[i])); // Check arrays. EXPECT_EQ(arr->size(), arr1->size()); @@ -771,9 +808,9 @@ TEST(PDFArrayTest, CloneDirectObject) { CPDF_IndirectObjectHolder objects_holder; auto array = pdfium::MakeRetain<CPDF_Array>(); - array->AddNew<CPDF_Reference>(&objects_holder, 1234); + array->AppendNew<CPDF_Reference>(&objects_holder, 1234); ASSERT_EQ(1U, array->size()); - CPDF_Object* obj = array->GetObjectAt(0); + RetainPtr<const CPDF_Object> obj = array->GetObjectAt(0); ASSERT_TRUE(obj); EXPECT_TRUE(obj->IsReference()); @@ -783,17 +820,17 @@ RetainPtr<CPDF_Array> cloned_array = ToArray(std::move(cloned_array_object)); ASSERT_EQ(0U, cloned_array->size()); - CPDF_Object* cloned_obj = cloned_array->GetObjectAt(0); + RetainPtr<const CPDF_Object> cloned_obj = cloned_array->GetObjectAt(0); EXPECT_FALSE(cloned_obj); } TEST(PDFArrayTest, ConvertIndirect) { CPDF_IndirectObjectHolder objects_holder; auto array = pdfium::MakeRetain<CPDF_Array>(); - CPDF_Object* pObj = array->AddNew<CPDF_Number>(42); + auto pObj = array->AppendNew<CPDF_Number>(42); array->ConvertToIndirectObjectAt(0, &objects_holder); - CPDF_Object* pRef = array->GetObjectAt(0); - CPDF_Object* pNum = array->GetDirectObjectAt(0); + RetainPtr<const CPDF_Object> pRef = array->GetObjectAt(0); + RetainPtr<const CPDF_Object> pNum = array->GetDirectObjectAt(0); EXPECT_TRUE(pRef->IsReference()); EXPECT_TRUE(pNum->IsNumber()); EXPECT_NE(pObj, pRef); @@ -802,18 +839,18 @@ } TEST(PDFStreamTest, SetData) { - std::vector<uint8_t> data(100); - auto stream = pdfium::MakeRetain<CPDF_Stream>(); - stream->InitStream(data, pdfium::MakeRetain<CPDF_Dictionary>()); + DataVector<uint8_t> data(100); + auto stream = pdfium::MakeRetain<CPDF_Stream>( + data, pdfium::MakeRetain<CPDF_Dictionary>()); EXPECT_EQ(static_cast<int>(data.size()), stream->GetDict()->GetIntegerFor(pdfium::stream::kLength)); - stream->GetDict()->SetNewFor<CPDF_String>(pdfium::stream::kFilter, - L"SomeFilter"); - stream->GetDict()->SetNewFor<CPDF_String>(pdfium::stream::kDecodeParms, - L"SomeParams"); + stream->GetMutableDict()->SetNewFor<CPDF_String>(pdfium::stream::kFilter, + L"SomeFilter"); + stream->GetMutableDict()->SetNewFor<CPDF_String>(pdfium::stream::kDecodeParms, + L"SomeParams"); - std::vector<uint8_t> new_data(data.size() * 2); + DataVector<uint8_t> new_data(data.size() * 2); stream->SetData(new_data); // The "Length" field should be updated for new data size. @@ -828,18 +865,18 @@ } TEST(PDFStreamTest, SetDataAndRemoveFilter) { - std::vector<uint8_t> data(100); - auto stream = pdfium::MakeRetain<CPDF_Stream>(); - stream->InitStream(data, pdfium::MakeRetain<CPDF_Dictionary>()); + DataVector<uint8_t> data(100); + auto stream = pdfium::MakeRetain<CPDF_Stream>( + data, pdfium::MakeRetain<CPDF_Dictionary>()); EXPECT_EQ(static_cast<int>(data.size()), stream->GetDict()->GetIntegerFor(pdfium::stream::kLength)); - stream->GetDict()->SetNewFor<CPDF_String>(pdfium::stream::kFilter, - L"SomeFilter"); - stream->GetDict()->SetNewFor<CPDF_String>(pdfium::stream::kDecodeParms, - L"SomeParams"); + stream->GetMutableDict()->SetNewFor<CPDF_String>(pdfium::stream::kFilter, + L"SomeFilter"); + stream->GetMutableDict()->SetNewFor<CPDF_String>(pdfium::stream::kDecodeParms, + L"SomeParams"); - std::vector<uint8_t> new_data(data.size() * 2); + DataVector<uint8_t> new_data(data.size() * 2); stream->SetDataAndRemoveFilter(new_data); // The "Length" field should be updated for new data size. EXPECT_EQ(static_cast<int>(new_data.size()), @@ -854,20 +891,16 @@ static constexpr uint32_t kBufSize = 100; // The length field should be created on stream create. { - std::unique_ptr<uint8_t, FxFreeDeleter> data; - data.reset(FX_Alloc(uint8_t, kBufSize)); auto stream = pdfium::MakeRetain<CPDF_Stream>( - std::move(data), kBufSize, pdfium::MakeRetain<CPDF_Dictionary>()); + DataVector<uint8_t>(kBufSize), pdfium::MakeRetain<CPDF_Dictionary>()); EXPECT_EQ(static_cast<int>(kBufSize), stream->GetDict()->GetIntegerFor(pdfium::stream::kLength)); } // The length field should be corrected on stream create. { - std::unique_ptr<uint8_t, FxFreeDeleter> data; - data.reset(FX_Alloc(uint8_t, kBufSize)); auto dict = pdfium::MakeRetain<CPDF_Dictionary>(); dict->SetNewFor<CPDF_Number>(pdfium::stream::kLength, 30000); - auto stream = pdfium::MakeRetain<CPDF_Stream>(std::move(data), kBufSize, + auto stream = pdfium::MakeRetain<CPDF_Stream>(DataVector<uint8_t>(kBufSize), std::move(dict)); EXPECT_EQ(static_cast<int>(kBufSize), stream->GetDict()->GetIntegerFor(pdfium::stream::kLength)); @@ -879,7 +912,7 @@ auto dict = pdfium::MakeRetain<CPDF_Dictionary>(); dict->SetNewFor<CPDF_Reference>("foo", &objects_holder, 1234); ASSERT_EQ(1U, dict->size()); - CPDF_Object* obj = dict->GetObjectFor("foo"); + RetainPtr<const CPDF_Object> obj = dict->GetObjectFor("foo"); ASSERT_TRUE(obj); EXPECT_TRUE(obj->IsReference()); @@ -890,7 +923,7 @@ RetainPtr<CPDF_Dictionary> cloned_dict = ToDictionary(std::move(cloned_dict_object)); ASSERT_EQ(0U, cloned_dict->size()); - CPDF_Object* cloned_obj = cloned_dict->GetObjectFor("foo"); + RetainPtr<const CPDF_Object> cloned_obj = cloned_dict->GetObjectFor("foo"); EXPECT_FALSE(cloned_obj); } @@ -898,44 +931,43 @@ { // Create a dictionary/array pair with a reference loop. auto arr_obj = pdfium::MakeRetain<CPDF_Array>(); - CPDF_Dictionary* dict_obj = arr_obj->InsertNewAt<CPDF_Dictionary>(0); + auto dict_obj = arr_obj->InsertNewAt<CPDF_Dictionary>(0); dict_obj->SetFor("arr", arr_obj); // Clone this object to see whether stack overflow will be triggered. RetainPtr<CPDF_Array> cloned_array = ToArray(arr_obj->Clone()); // Cloned object should be the same as the original. ASSERT_TRUE(cloned_array); EXPECT_EQ(1u, cloned_array->size()); - CPDF_Object* cloned_dict = cloned_array->GetObjectAt(0); + RetainPtr<const CPDF_Object> cloned_dict = cloned_array->GetObjectAt(0); ASSERT_TRUE(cloned_dict); ASSERT_TRUE(cloned_dict->IsDictionary()); // Recursively referenced object is not cloned. - EXPECT_EQ(nullptr, cloned_dict->AsDictionary()->GetObjectFor("arr")); + EXPECT_FALSE(cloned_dict->AsDictionary()->GetObjectFor("arr")); dict_obj->RemoveFor("arr"); // Break deliberate cycle for cleanup. } { // Create a dictionary/stream pair with a reference loop. auto dict_obj = pdfium::MakeRetain<CPDF_Dictionary>(); - CPDF_Stream* stream_obj = - dict_obj->SetNewFor<CPDF_Stream>("stream", nullptr, 0, dict_obj); + auto stream_obj = dict_obj->SetNewFor<CPDF_Stream>("stream", dict_obj); // Clone this object to see whether stack overflow will be triggered. RetainPtr<CPDF_Stream> cloned_stream = ToStream(stream_obj->Clone()); // Cloned object should be the same as the original. ASSERT_TRUE(cloned_stream); - CPDF_Object* cloned_dict = cloned_stream->GetDict(); + RetainPtr<const CPDF_Object> cloned_dict = cloned_stream->GetDict(); ASSERT_TRUE(cloned_dict); ASSERT_TRUE(cloned_dict->IsDictionary()); // Recursively referenced object is not cloned. - EXPECT_EQ(nullptr, cloned_dict->AsDictionary()->GetObjectFor("stream")); + EXPECT_FALSE(cloned_dict->AsDictionary()->GetObjectFor("stream")); dict_obj->RemoveFor("stream"); // Break deliberate cycle for cleanup. } { CPDF_IndirectObjectHolder objects_holder; // Create an object with a reference loop. - CPDF_Dictionary* dict_obj = objects_holder.NewIndirect<CPDF_Dictionary>(); - RetainPtr<CPDF_Array> arr_obj = pdfium::MakeRetain<CPDF_Array>(); + auto dict_obj = objects_holder.NewIndirect<CPDF_Dictionary>(); + auto arr_obj = pdfium::MakeRetain<CPDF_Array>(); arr_obj->InsertNewAt<CPDF_Reference>(0, &objects_holder, dict_obj->GetObjNum()); - CPDF_Object* elem0 = arr_obj->GetObjectAt(0); + RetainPtr<const CPDF_Object> elem0 = arr_obj->GetObjectAt(0); dict_obj->SetFor("arr", std::move(arr_obj)); EXPECT_EQ(1u, dict_obj->GetObjNum()); ASSERT_TRUE(elem0); @@ -948,12 +980,12 @@ ToDictionary(dict_obj->CloneDirectObject()); // Cloned object should be the same as the original. ASSERT_TRUE(cloned_dict); - CPDF_Object* cloned_arr = cloned_dict->GetObjectFor("arr"); + RetainPtr<const CPDF_Object> cloned_arr = cloned_dict->GetObjectFor("arr"); ASSERT_TRUE(cloned_arr); ASSERT_TRUE(cloned_arr->IsArray()); EXPECT_EQ(0U, cloned_arr->AsArray()->size()); // Recursively referenced object is not cloned. - EXPECT_EQ(nullptr, cloned_arr->AsArray()->GetObjectAt(0)); + EXPECT_FALSE(cloned_arr->AsArray()->GetObjectAt(0)); dict_obj->RemoveFor("arr"); // Break deliberate cycle for cleanup. } } @@ -961,10 +993,10 @@ TEST(PDFDictionaryTest, ConvertIndirect) { CPDF_IndirectObjectHolder objects_holder; auto dict = pdfium::MakeRetain<CPDF_Dictionary>(); - CPDF_Object* pObj = dict->SetNewFor<CPDF_Number>("clams", 42); + auto pObj = dict->SetNewFor<CPDF_Number>("clams", 42); dict->ConvertToIndirectObjectFor("clams", &objects_holder); - CPDF_Object* pRef = dict->GetObjectFor("clams"); - CPDF_Object* pNum = dict->GetDirectObjectFor("clams"); + RetainPtr<const CPDF_Object> pRef = dict->GetObjectFor("clams"); + RetainPtr<const CPDF_Object> pNum = dict->GetDirectObjectFor("clams"); EXPECT_TRUE(pRef->IsReference()); EXPECT_TRUE(pNum->IsNumber()); EXPECT_NE(pObj, pRef); @@ -974,7 +1006,7 @@ TEST(PDFDictionaryTest, ExtractObjectOnRemove) { auto dict = pdfium::MakeRetain<CPDF_Dictionary>(); - CPDF_Object* pObj = dict->SetNewFor<CPDF_Number>("child", 42); + auto pObj = dict->SetNewFor<CPDF_Number>("child", 42); auto extracted_object = dict->RemoveFor("child"); EXPECT_EQ(pObj, extracted_object.Get()); @@ -983,7 +1015,7 @@ } TEST(PDFRefernceTest, MakeReferenceToReference) { - auto obj_holder = pdfium::MakeUnique<CPDF_IndirectObjectHolder>(); + auto obj_holder = std::make_unique<CPDF_IndirectObjectHolder>(); auto original_ref = pdfium::MakeRetain<CPDF_Reference>(obj_holder.get(), 42); original_ref->SetObjNum(1952); ASSERT_FALSE(original_ref->IsInline());
diff --git a/core/fpdfapi/parser/cpdf_object_walker.cpp b/core/fpdfapi/parser/cpdf_object_walker.cpp index efd4a5c..71acdfb 100644 --- a/core/fpdfapi/parser/cpdf_object_walker.cpp +++ b/core/fpdfapi/parser/cpdf_object_walker.cpp
@@ -1,4 +1,4 @@ -// Copyright 2017 PDFium Authors. All rights reserved. +// Copyright 2017 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -9,21 +9,22 @@ #include "core/fpdfapi/parser/cpdf_array.h" #include "core/fpdfapi/parser/cpdf_dictionary.h" #include "core/fpdfapi/parser/cpdf_stream.h" -#include "third_party/base/ptr_util.h" +#include "third_party/base/check.h" namespace { class StreamIterator final : public CPDF_ObjectWalker::SubobjectIterator { public: - explicit StreamIterator(const CPDF_Stream* stream) - : SubobjectIterator(stream) {} - ~StreamIterator() override {} + explicit StreamIterator(RetainPtr<const CPDF_Stream> stream) + : SubobjectIterator(std::move(stream)) {} + + ~StreamIterator() override = default; bool IsFinished() const override { return IsStarted() && is_finished_; } - const CPDF_Object* IncrementImpl() override { - ASSERT(IsStarted()); - ASSERT(!IsFinished()); + RetainPtr<const CPDF_Object> IncrementImpl() override { + DCHECK(IsStarted()); + DCHECK(!IsFinished()); is_finished_ = true; return object()->GetDict(); } @@ -36,25 +37,26 @@ class DictionaryIterator final : public CPDF_ObjectWalker::SubobjectIterator { public: - explicit DictionaryIterator(const CPDF_Dictionary* dictionary) + explicit DictionaryIterator(RetainPtr<const CPDF_Dictionary> dictionary) : SubobjectIterator(dictionary), locker_(dictionary) {} - ~DictionaryIterator() override {} + + ~DictionaryIterator() override = default; bool IsFinished() const override { return IsStarted() && dict_iterator_ == locker_.end(); } - const CPDF_Object* IncrementImpl() override { - ASSERT(IsStarted()); - ASSERT(!IsFinished()); - const CPDF_Object* result = dict_iterator_->second.Get(); + RetainPtr<const CPDF_Object> IncrementImpl() override { + DCHECK(IsStarted()); + DCHECK(!IsFinished()); + RetainPtr<const CPDF_Object> result = dict_iterator_->second; dict_key_ = dict_iterator_->first; ++dict_iterator_; return result; } void Start() override { - ASSERT(!IsStarted()); + DCHECK(!IsStarted()); dict_iterator_ = locker_.begin(); } @@ -68,19 +70,19 @@ class ArrayIterator final : public CPDF_ObjectWalker::SubobjectIterator { public: - explicit ArrayIterator(const CPDF_Array* array) + explicit ArrayIterator(RetainPtr<const CPDF_Array> array) : SubobjectIterator(array), locker_(array) {} - ~ArrayIterator() override {} + ~ArrayIterator() override = default; bool IsFinished() const override { return IsStarted() && arr_iterator_ == locker_.end(); } - const CPDF_Object* IncrementImpl() override { - ASSERT(IsStarted()); - ASSERT(!IsFinished()); - const CPDF_Object* result = arr_iterator_->Get(); + RetainPtr<const CPDF_Object> IncrementImpl() override { + DCHECK(IsStarted()); + DCHECK(!IsFinished()); + RetainPtr<const CPDF_Object> result = *arr_iterator_; ++arr_iterator_; return result; } @@ -94,15 +96,15 @@ } // namespace -CPDF_ObjectWalker::SubobjectIterator::~SubobjectIterator() {} +CPDF_ObjectWalker::SubobjectIterator::~SubobjectIterator() = default; -const CPDF_Object* CPDF_ObjectWalker::SubobjectIterator::Increment() { +RetainPtr<const CPDF_Object> CPDF_ObjectWalker::SubobjectIterator::Increment() { if (!IsStarted()) { Start(); is_started_ = true; } while (!IsFinished()) { - const CPDF_Object* result = IncrementImpl(); + RetainPtr<const CPDF_Object> result = IncrementImpl(); if (result) return result; } @@ -110,46 +112,44 @@ } CPDF_ObjectWalker::SubobjectIterator::SubobjectIterator( - const CPDF_Object* object) - : object_(object) { - ASSERT(object_); + RetainPtr<const CPDF_Object> object) + : object_(std::move(object)) { + DCHECK(object_); } // static std::unique_ptr<CPDF_ObjectWalker::SubobjectIterator> -CPDF_ObjectWalker::MakeIterator(const CPDF_Object* object) { +CPDF_ObjectWalker::MakeIterator(RetainPtr<const CPDF_Object> object) { if (object->IsStream()) - return pdfium::MakeUnique<StreamIterator>(object->AsStream()); + return std::make_unique<StreamIterator>(ToStream(object)); if (object->IsDictionary()) - return pdfium::MakeUnique<DictionaryIterator>(object->AsDictionary()); + return std::make_unique<DictionaryIterator>(ToDictionary(object)); if (object->IsArray()) - return pdfium::MakeUnique<ArrayIterator>(object->AsArray()); + return std::make_unique<ArrayIterator>(ToArray(object)); return nullptr; } -CPDF_ObjectWalker::CPDF_ObjectWalker(const CPDF_Object* root) - : next_object_(root) {} +CPDF_ObjectWalker::CPDF_ObjectWalker(RetainPtr<const CPDF_Object> root) + : next_object_(std::move(root)) {} CPDF_ObjectWalker::~CPDF_ObjectWalker() = default; -const CPDF_Object* CPDF_ObjectWalker::GetNext() { +RetainPtr<const CPDF_Object> CPDF_ObjectWalker::GetNext() { while (!stack_.empty() || next_object_) { if (next_object_) { - auto new_iterator = MakeIterator(next_object_.Get()); + auto new_iterator = MakeIterator(next_object_); if (new_iterator) { // Schedule walk within composite objects. stack_.push(std::move(new_iterator)); } - auto* result = next_object_.Get(); - next_object_ = nullptr; - return result; + return std::move(next_object_); // next_object_ is NULL after move. } SubobjectIterator* it = stack_.top().get(); if (it->IsFinished()) { stack_.pop(); } else { - next_object_.Reset(it->Increment()); + next_object_ = it->Increment(); parent_object_.Reset(it->object()); dict_key_ = parent_object_->IsDictionary() ? static_cast<DictionaryIterator*>(it)->dict_key() @@ -167,3 +167,12 @@ return; stack_.pop(); } + +CPDF_NonConstObjectWalker::CPDF_NonConstObjectWalker( + RetainPtr<CPDF_Object> root) + : CPDF_ObjectWalker(std::move(root)) {} + +RetainPtr<CPDF_Object> CPDF_NonConstObjectWalker::GetNext() { + return pdfium::WrapRetain( + const_cast<CPDF_Object*>(CPDF_ObjectWalker::GetNext().Get())); +}
diff --git a/core/fpdfapi/parser/cpdf_object_walker.h b/core/fpdfapi/parser/cpdf_object_walker.h index d019286..c779da1 100644 --- a/core/fpdfapi/parser/cpdf_object_walker.h +++ b/core/fpdfapi/parser/cpdf_object_walker.h
@@ -1,4 +1,4 @@ -// Copyright 2017 PDFium Authors. All rights reserved. +// Copyright 2017 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -8,7 +8,7 @@ #include <memory> #include <stack> -#include "core/fxcrt/fx_string.h" +#include "core/fxcrt/bytestring.h" #include "core/fxcrt/retain_ptr.h" class CPDF_Object; @@ -22,13 +22,13 @@ virtual ~SubobjectIterator(); virtual bool IsFinished() const = 0; bool IsStarted() const { return is_started_; } - const CPDF_Object* Increment(); + RetainPtr<const CPDF_Object> Increment(); const CPDF_Object* object() const { return object_.Get(); } protected: - explicit SubobjectIterator(const CPDF_Object* object); + explicit SubobjectIterator(RetainPtr<const CPDF_Object> object); - virtual const CPDF_Object* IncrementImpl() = 0; + virtual RetainPtr<const CPDF_Object> IncrementImpl() = 0; virtual void Start() = 0; private: @@ -36,10 +36,10 @@ bool is_started_ = false; }; - explicit CPDF_ObjectWalker(const CPDF_Object* root); + explicit CPDF_ObjectWalker(RetainPtr<const CPDF_Object> root); ~CPDF_ObjectWalker(); - const CPDF_Object* GetNext(); + RetainPtr<const CPDF_Object> GetNext(); void SkipWalkIntoCurrentObject(); size_t current_depth() const { return current_depth_; } @@ -48,7 +48,7 @@ private: static std::unique_ptr<SubobjectIterator> MakeIterator( - const CPDF_Object* object); + RetainPtr<const CPDF_Object> object); RetainPtr<const CPDF_Object> next_object_; RetainPtr<const CPDF_Object> parent_object_; @@ -59,12 +59,8 @@ class CPDF_NonConstObjectWalker final : public CPDF_ObjectWalker { public: - explicit CPDF_NonConstObjectWalker(CPDF_Object* root) - : CPDF_ObjectWalker(root) {} - - CPDF_Object* GetNext() { - return const_cast<CPDF_Object*>(CPDF_ObjectWalker::GetNext()); - } + explicit CPDF_NonConstObjectWalker(RetainPtr<CPDF_Object> root); + RetainPtr<CPDF_Object> GetNext(); }; #endif // CORE_FPDFAPI_PARSER_CPDF_OBJECT_WALKER_H_
diff --git a/core/fpdfapi/parser/cpdf_object_walker_unittest.cpp b/core/fpdfapi/parser/cpdf_object_walker_unittest.cpp index 4dde72f..ab0c2c3 100644 --- a/core/fpdfapi/parser/cpdf_object_walker_unittest.cpp +++ b/core/fpdfapi/parser/cpdf_object_walker_unittest.cpp
@@ -1,4 +1,4 @@ -// Copyright 2017 PDFium Authors. All rights reserved. +// Copyright 2017 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -18,14 +18,13 @@ #include "core/fpdfapi/parser/cpdf_stream.h" #include "core/fpdfapi/parser/cpdf_string.h" #include "testing/gtest/include/gtest/gtest.h" -#include "third_party/base/ptr_util.h" namespace { -std::string Walk(CPDF_Object* object) { +std::string Walk(RetainPtr<CPDF_Object> object) { std::ostringstream result; - CPDF_ObjectWalker walker(object); - while (const CPDF_Object* obj = walker.GetNext()) { + CPDF_ObjectWalker walker(std::move(object)); + while (RetainPtr<const CPDF_Object> obj = walker.GetNext()) { if (obj->IsDictionary()) result << " Dict"; else if (obj->IsArray()) @@ -54,64 +53,63 @@ } // namespace -TEST(CPDF_ObjectWalkerTest, Simple) { - EXPECT_EQ(Walk(pdfium::MakeRetain<CPDF_Null>().Get()), "Null"); - EXPECT_EQ(Walk(pdfium::MakeRetain<CPDF_Dictionary>().Get()), "Dict"); - EXPECT_EQ(Walk(pdfium::MakeRetain<CPDF_Array>().Get()), "Arr"); - EXPECT_EQ(Walk(pdfium::MakeRetain<CPDF_String>().Get()), "Str"); - EXPECT_EQ(Walk(pdfium::MakeRetain<CPDF_Boolean>().Get()), "Bool"); - EXPECT_EQ(Walk(pdfium::MakeRetain<CPDF_Stream>().Get()), "Stream"); - EXPECT_EQ(Walk(pdfium::MakeRetain<CPDF_Reference>(nullptr, 0).Get()), "Ref"); +TEST(ObjectWalkerTest, Simple) { + EXPECT_EQ(Walk(pdfium::MakeRetain<CPDF_Null>()), "Null"); + EXPECT_EQ(Walk(pdfium::MakeRetain<CPDF_Dictionary>()), "Dict"); + EXPECT_EQ(Walk(pdfium::MakeRetain<CPDF_Array>()), "Arr"); + EXPECT_EQ(Walk(pdfium::MakeRetain<CPDF_String>()), "Str"); + EXPECT_EQ(Walk(pdfium::MakeRetain<CPDF_Boolean>()), "Bool"); + EXPECT_EQ(Walk(pdfium::MakeRetain<CPDF_Stream>()), "Stream"); + EXPECT_EQ(Walk(pdfium::MakeRetain<CPDF_Reference>(nullptr, 0)), "Ref"); } -TEST(CPDF_ObjectWalkerTest, CombinedObject) { +TEST(ObjectWalkerTest, CombinedObject) { auto dict = pdfium::MakeRetain<CPDF_Dictionary>(); dict->SetFor("1", pdfium::MakeRetain<CPDF_String>()); dict->SetFor("2", pdfium::MakeRetain<CPDF_Boolean>()); auto array = pdfium::MakeRetain<CPDF_Array>(); - array->Add(pdfium::MakeRetain<CPDF_Reference>(nullptr, 0)); - array->Add(pdfium::MakeRetain<CPDF_Null>()); - array->Add(pdfium::MakeRetain<CPDF_Stream>( - nullptr, 0, pdfium::MakeRetain<CPDF_Dictionary>())); + array->Append(pdfium::MakeRetain<CPDF_Reference>(nullptr, 0)); + array->Append(pdfium::MakeRetain<CPDF_Null>()); + array->Append( + pdfium::MakeRetain<CPDF_Stream>(pdfium::MakeRetain<CPDF_Dictionary>())); dict->SetFor("3", std::move(array)); // The last number for stream length. - EXPECT_EQ(Walk(dict.Get()), "Dict Str Bool Arr Ref Null Stream Dict Num"); + EXPECT_EQ(Walk(dict), "Dict Str Bool Arr Ref Null Stream Dict Num"); } -TEST(CPDF_ObjectWalkerTest, GetParent) { +TEST(ObjectWalkerTest, GetParent) { auto level_4 = pdfium::MakeRetain<CPDF_Number>(0); auto level_3 = pdfium::MakeRetain<CPDF_Dictionary>(); level_3->SetFor("Length", std::move(level_4)); - auto level_2 = - pdfium::MakeRetain<CPDF_Stream>(nullptr, 0, std::move(level_3)); + auto level_2 = pdfium::MakeRetain<CPDF_Stream>(std::move(level_3)); auto level_1 = pdfium::MakeRetain<CPDF_Array>(); - level_1->Add(std::move(level_2)); + level_1->Append(std::move(level_2)); auto level_0 = pdfium::MakeRetain<CPDF_Dictionary>(); level_0->SetFor("Array", std::move(level_1)); // We have <</Array [ stream( << /Length 0 >>) ]>> // In this case each step will increase depth. // And on each step the prev object should be parent for current. - const CPDF_Object* cur_parent = nullptr; - CPDF_ObjectWalker walker(level_0.Get()); - while (const CPDF_Object* obj = walker.GetNext()) { + RetainPtr<const CPDF_Object> cur_parent; + CPDF_ObjectWalker walker(level_0); + while (RetainPtr<const CPDF_Object> obj = walker.GetNext()) { EXPECT_EQ(cur_parent, walker.GetParent()); - cur_parent = obj; + cur_parent = std::move(obj); } } -TEST(CPDF_ObjectWalkerTest, SkipWalkIntoCurrentObject) { +TEST(ObjectWalkerTest, SkipWalkIntoCurrentObject) { auto root_array = pdfium::MakeRetain<CPDF_Array>(); // Add 2 null objects into |root_array|. [ null1, null2 ] - root_array->AddNew<CPDF_Null>(); - root_array->AddNew<CPDF_Null>(); + root_array->AppendNew<CPDF_Null>(); + root_array->AppendNew<CPDF_Null>(); // |root_array| will contain 4 null objects after this. // [ null1, null2, [ null3, null4 ] ] - root_array->Add(root_array->Clone()); + root_array->Append(root_array->Clone()); int non_array_objects = 0; - CPDF_ObjectWalker walker(root_array.Get()); - while (const CPDF_Object* obj = walker.GetNext()) { + CPDF_ObjectWalker walker(root_array); + while (RetainPtr<const CPDF_Object> obj = walker.GetNext()) { if (obj != root_array && obj->IsArray()) { // skip other array except root. walker.SkipWalkIntoCurrentObject(); @@ -123,7 +121,7 @@ EXPECT_EQ(2, non_array_objects); } -TEST(CPDF_ObjectWalkerTest, DictionaryKey) { +TEST(ObjectWalkerTest, DictionaryKey) { auto dict = pdfium::MakeRetain<CPDF_Dictionary>(); dict->SetFor("1", pdfium::MakeRetain<CPDF_Null>()); dict->SetFor("2", pdfium::MakeRetain<CPDF_Null>()); @@ -131,8 +129,8 @@ dict->SetFor("4", pdfium::MakeRetain<CPDF_Null>()); dict->SetFor("5", pdfium::MakeRetain<CPDF_Null>()); - CPDF_ObjectWalker walker(dict.Get()); - while (const CPDF_Object* obj = walker.GetNext()) { + CPDF_ObjectWalker walker(dict); + while (RetainPtr<const CPDF_Object> obj = walker.GetNext()) { if (dict == obj) { // Ignore root dictinary object continue;
diff --git a/core/fpdfapi/parser/cpdf_page_object_avail.cpp b/core/fpdfapi/parser/cpdf_page_object_avail.cpp index 6673885..af46e70 100644 --- a/core/fpdfapi/parser/cpdf_page_object_avail.cpp +++ b/core/fpdfapi/parser/cpdf_page_object_avail.cpp
@@ -1,17 +1,18 @@ -// Copyright 2017 PDFium Authors. All rights reserved. +// Copyright 2017 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "core/fpdfapi/parser/cpdf_page_object_avail.h" #include "core/fpdfapi/parser/cpdf_dictionary.h" +#include "core/fpdfapi/parser/fpdf_parser_utility.h" -CPDF_PageObjectAvail::~CPDF_PageObjectAvail() {} +CPDF_PageObjectAvail::~CPDF_PageObjectAvail() = default; bool CPDF_PageObjectAvail::ExcludeObject(const CPDF_Object* object) const { if (CPDF_ObjectAvail::ExcludeObject(object)) return true; - return object->IsDictionary() && - object->GetDict()->GetStringFor("Type") == "Page"; + // See ISO 32000-1:2008 spec, table 30. + return ValidateDictType(ToDictionary(object), "Page"); }
diff --git a/core/fpdfapi/parser/cpdf_page_object_avail.h b/core/fpdfapi/parser/cpdf_page_object_avail.h index bb9e80a..01a2c6a 100644 --- a/core/fpdfapi/parser/cpdf_page_object_avail.h +++ b/core/fpdfapi/parser/cpdf_page_object_avail.h
@@ -1,4 +1,4 @@ -// Copyright 2017 PDFium Authors. All rights reserved. +// Copyright 2017 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file.
diff --git a/core/fpdfapi/parser/cpdf_page_object_avail_unittest.cpp b/core/fpdfapi/parser/cpdf_page_object_avail_unittest.cpp index 6a76118..2486fed 100644 --- a/core/fpdfapi/parser/cpdf_page_object_avail_unittest.cpp +++ b/core/fpdfapi/parser/cpdf_page_object_avail_unittest.cpp
@@ -1,38 +1,37 @@ -// Copyright 2017 PDFium Authors. All rights reserved. +// Copyright 2017 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "core/fpdfapi/parser/cpdf_page_object_avail.h" #include <map> -#include <memory> #include <utility> #include "core/fpdfapi/parser/cpdf_array.h" #include "core/fpdfapi/parser/cpdf_dictionary.h" #include "core/fpdfapi/parser/cpdf_indirect_object_holder.h" +#include "core/fpdfapi/parser/cpdf_name.h" #include "core/fpdfapi/parser/cpdf_read_validator.h" #include "core/fpdfapi/parser/cpdf_reference.h" #include "core/fpdfapi/parser/cpdf_string.h" #include "core/fxcrt/fx_stream.h" #include "testing/gtest/include/gtest/gtest.h" #include "testing/invalid_seekable_read_stream.h" -#include "third_party/base/ptr_util.h" +#include "third_party/base/check.h" namespace { class TestReadValidator final : public CPDF_ReadValidator { public: - template <typename T, typename... Args> - friend RetainPtr<T> pdfium::MakeRetain(Args&&... args); + CONSTRUCT_VIA_MAKE_RETAIN; - void SimulateReadError() { ReadBlockAtOffset(nullptr, 0, 1); } + void SimulateReadError() { ReadBlockAtOffset({}, 0); } private: TestReadValidator() : CPDF_ReadValidator(pdfium::MakeRetain<InvalidSeekableReadStream>(100), nullptr) {} - ~TestReadValidator() override {} + ~TestReadValidator() override = default; }; class TestHolder final : public CPDF_IndirectObjectHolder { @@ -42,10 +41,10 @@ Available, }; TestHolder() : validator_(pdfium::MakeRetain<TestReadValidator>()) {} - ~TestHolder() override {} + ~TestHolder() override = default; // CPDF_IndirectObjectHolder overrides: - CPDF_Object* GetOrParseIndirectObject(uint32_t objnum) override { + RetainPtr<CPDF_Object> ParseIndirectObject(uint32_t objnum) override { auto it = objects_data_.find(objnum); if (it == objects_data_.end()) return nullptr; @@ -55,7 +54,7 @@ validator_->SimulateReadError(); return nullptr; } - return obj_data.object.Get(); + return obj_data.object; } RetainPtr<CPDF_ReadValidator> GetValidator() { return validator_; } @@ -66,13 +65,13 @@ ObjectData object_data; object_data.object = std::move(object); object_data.state = state; - ASSERT(objects_data_.find(objnum) == objects_data_.end()); + DCHECK(objects_data_.find(objnum) == objects_data_.end()); objects_data_[objnum] = std::move(object_data); } void SetObjectState(uint32_t objnum, ObjectState state) { auto it = objects_data_.find(objnum); - ASSERT(it != objects_data_.end()); + DCHECK(it != objects_data_.end()); ObjectData& obj_data = it->second; obj_data.state = state; } @@ -95,22 +94,23 @@ } // namespace -TEST(CPDF_PageObjectAvailTest, ExcludePages) { +TEST(PageObjectAvailTest, ExcludePages) { TestHolder holder; holder.AddObject(1, pdfium::MakeRetain<CPDF_Dictionary>(), TestHolder::ObjectState::Available); - holder.GetTestObject(1)->GetDict()->SetNewFor<CPDF_Reference>("Kids", &holder, - 2); + holder.GetTestObject(1)->GetMutableDict()->SetNewFor<CPDF_Reference>( + "Kids", &holder, 2); holder.AddObject(2, pdfium::MakeRetain<CPDF_Array>(), TestHolder::ObjectState::Available); - holder.GetTestObject(2)->AsArray()->AddNew<CPDF_Reference>(&holder, 3); + holder.GetTestObject(2)->AsMutableArray()->AppendNew<CPDF_Reference>(&holder, + 3); holder.AddObject(3, pdfium::MakeRetain<CPDF_Dictionary>(), TestHolder::ObjectState::Available); - holder.GetTestObject(3)->GetDict()->SetFor( - "Type", pdfium::MakeRetain<CPDF_String>(nullptr, "Page", false)); - holder.GetTestObject(3)->GetDict()->SetNewFor<CPDF_Reference>("OtherPageData", - &holder, 4); + holder.GetTestObject(3)->GetMutableDict()->SetFor( + "Type", pdfium::MakeRetain<CPDF_Name>(nullptr, "Page")); + holder.GetTestObject(3)->GetMutableDict()->SetNewFor<CPDF_Reference>( + "OtherPageData", &holder, 4); // Add unavailable object related to other page. holder.AddObject( 4, pdfium::MakeRetain<CPDF_String>(nullptr, "Other page data", false), @@ -119,5 +119,5 @@ CPDF_PageObjectAvail avail(holder.GetValidator(), &holder, 1); // Now object should be available, although the object '4' is not available, // because it is in skipped other page. - EXPECT_EQ(CPDF_DataAvail::DocAvailStatus::DataAvailable, avail.CheckAvail()); + EXPECT_EQ(CPDF_DataAvail::kDataAvailable, avail.CheckAvail()); }
diff --git a/core/fpdfapi/parser/cpdf_parser.cpp b/core/fpdfapi/parser/cpdf_parser.cpp index 3e2819b..302aec1 100644 --- a/core/fpdfapi/parser/cpdf_parser.cpp +++ b/core/fpdfapi/parser/cpdf_parser.cpp
@@ -1,4 +1,4 @@ -// Copyright 2016 PDFium Authors. All rights reserved. +// Copyright 2016 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -6,6 +6,9 @@ #include "core/fpdfapi/parser/cpdf_parser.h" +#include <ctype.h> +#include <stdint.h> + #include <algorithm> #include <utility> #include <vector> @@ -25,10 +28,15 @@ #include "core/fpdfapi/parser/cpdf_syntax_parser.h" #include "core/fpdfapi/parser/fpdf_parser_utility.h" #include "core/fxcrt/autorestorer.h" +#include "core/fxcrt/data_vector.h" #include "core/fxcrt/fx_extension.h" #include "core/fxcrt/fx_safe_types.h" -#include "third_party/base/ptr_util.h" -#include "third_party/base/stl_util.h" +#include "core/fxcrt/scoped_set_insertion.h" +#include "third_party/base/check.h" +#include "third_party/base/check_op.h" +#include "third_party/base/containers/contains.h" +#include "third_party/base/notreached.h" +#include "third_party/base/span.h" namespace { @@ -39,13 +47,99 @@ // "%PDF-1.7\n" constexpr FX_FILESIZE kPDFHeaderSize = 9; -uint32_t GetVarInt(const uint8_t* p, int32_t n) { +// The required number of fields in a /W array in a cross-reference stream +// dictionary. +constexpr size_t kMinFieldCount = 3; + +// V4 trailers are inline. +constexpr uint32_t kNoV4TrailerObjectNumber = 0; + +struct CrossRefV5IndexEntry { + uint32_t start_obj_num; + uint32_t obj_count; +}; + +CPDF_Parser::ObjectType GetObjectTypeFromCrossRefStreamType( + uint32_t cross_ref_stream_type) { + switch (cross_ref_stream_type) { + case 0: + return CPDF_Parser::ObjectType::kFree; + case 1: + return CPDF_Parser::ObjectType::kNotCompressed; + case 2: + return CPDF_Parser::ObjectType::kCompressed; + default: + return CPDF_Parser::ObjectType::kNull; + } +} + +// Use the Get*XRefStreamEntry() functions below, instead of calling this +// directly. +uint32_t GetVarInt(pdfium::span<const uint8_t> input) { uint32_t result = 0; - for (int32_t i = 0; i < n; ++i) - result = result * 256 + p[i]; + for (uint8_t c : input) + result = result * 256 + c; return result; } +// The following 3 functions retrieve variable length entries from +// cross-reference streams, as described in ISO 32000-1:2008 table 18. There are +// only 3 fields for any given entry. +uint32_t GetFirstXRefStreamEntry(pdfium::span<const uint8_t> entry_span, + pdfium::span<const uint32_t> field_widths) { + return GetVarInt(entry_span.first(field_widths[0])); +} + +uint32_t GetSecondXRefStreamEntry(pdfium::span<const uint8_t> entry_span, + pdfium::span<const uint32_t> field_widths) { + return GetVarInt(entry_span.subspan(field_widths[0], field_widths[1])); +} + +uint32_t GetThirdXRefStreamEntry(pdfium::span<const uint8_t> entry_span, + pdfium::span<const uint32_t> field_widths) { + return GetVarInt( + entry_span.subspan(field_widths[0] + field_widths[1], field_widths[2])); +} + +std::vector<CrossRefV5IndexEntry> GetCrossRefV5Indices(const CPDF_Array* array, + uint32_t size) { + std::vector<CrossRefV5IndexEntry> indices; + if (array) { + for (size_t i = 0; i < array->size() / 2; i++) { + RetainPtr<const CPDF_Number> pStartNumObj = array->GetNumberAt(i * 2); + if (!pStartNumObj) + continue; + + RetainPtr<const CPDF_Number> pCountObj = array->GetNumberAt(i * 2 + 1); + if (!pCountObj) + continue; + + int nStartNum = pStartNumObj->GetInteger(); + int nCount = pCountObj->GetInteger(); + if (nStartNum < 0 || nCount <= 0) + continue; + + indices.push_back( + {static_cast<uint32_t>(nStartNum), static_cast<uint32_t>(nCount)}); + } + } + + if (indices.empty()) + indices.push_back({0, size}); + return indices; +} + +std::vector<uint32_t> GetFieldWidths(const CPDF_Array* array) { + std::vector<uint32_t> results; + if (!array) + return results; + + CPDF_ArrayLocker locker(array); + for (const auto& obj : locker) + results.push_back(obj->GetInteger()); + return results; +} + class ObjectsHolderStub final : public CPDF_Parser::ParsedObjectsHolder { public: ObjectsHolderStub() = default; @@ -57,18 +151,16 @@ CPDF_Parser::CPDF_Parser(ParsedObjectsHolder* holder) : m_pObjectsHolder(holder), - m_CrossRefTable(pdfium::MakeUnique<CPDF_CrossRefTable>()) { + m_CrossRefTable(std::make_unique<CPDF_CrossRefTable>()) { if (!holder) { - m_pOwnedObjectsHolder = pdfium::MakeUnique<ObjectsHolderStub>(); + m_pOwnedObjectsHolder = std::make_unique<ObjectsHolderStub>(); m_pObjectsHolder = m_pOwnedObjectsHolder.get(); } } CPDF_Parser::CPDF_Parser() : CPDF_Parser(nullptr) {} -CPDF_Parser::~CPDF_Parser() { - ReleaseEncryptHandler(); -} +CPDF_Parser::~CPDF_Parser() = default; uint32_t CPDF_Parser::GetLastObjNum() const { return m_CrossRefTable->objects_info().empty() @@ -86,7 +178,7 @@ } CPDF_Parser::ObjectType CPDF_Parser::GetObjectType(uint32_t objnum) const { - ASSERT(IsValidObjectNumber(objnum)); + DCHECK(IsValidObjectNumber(objnum)); const auto* info = m_CrossRefTable->GetObjectInfo(objnum); return info ? info->type : ObjectType::kFree; } @@ -112,15 +204,15 @@ m_CrossRefTable->ShrinkObjectMap(size); } -bool CPDF_Parser::InitSyntaxParser( - const RetainPtr<CPDF_ReadValidator>& validator) { - const Optional<FX_FILESIZE> header_offset = GetHeaderOffset(validator); - if (!header_offset) +bool CPDF_Parser::InitSyntaxParser(RetainPtr<CPDF_ReadValidator> validator) { + const absl::optional<FX_FILESIZE> header_offset = GetHeaderOffset(validator); + if (!header_offset.has_value()) return false; - if (validator->GetSize() < *header_offset + kPDFHeaderSize) + if (validator->GetSize() < header_offset.value() + kPDFHeaderSize) return false; - m_pSyntax = pdfium::MakeUnique<CPDF_SyntaxParser>(validator, *header_offset); + m_pSyntax = std::make_unique<CPDF_SyntaxParser>(std::move(validator), + header_offset.value()); return ParseFileVersion(); } @@ -130,30 +222,30 @@ if (!m_pSyntax->GetCharAt(5, ch)) return false; - if (std::isdigit(ch)) + if (isdigit(ch)) m_FileVersion = FXSYS_DecimalCharToInt(static_cast<wchar_t>(ch)) * 10; if (!m_pSyntax->GetCharAt(7, ch)) return false; - if (std::isdigit(ch)) + if (isdigit(ch)) m_FileVersion += FXSYS_DecimalCharToInt(static_cast<wchar_t>(ch)); return true; } CPDF_Parser::Error CPDF_Parser::StartParse( - const RetainPtr<IFX_SeekableReadStream>& pFileAccess, - const char* password) { - if (!InitSyntaxParser( - pdfium::MakeRetain<CPDF_ReadValidator>(pFileAccess, nullptr))) + RetainPtr<IFX_SeekableReadStream> pFileAccess, + const ByteString& password) { + if (!InitSyntaxParser(pdfium::MakeRetain<CPDF_ReadValidator>( + std::move(pFileAccess), nullptr))) return FORMAT_ERROR; SetPassword(password); return StartParseInternal(); } CPDF_Parser::Error CPDF_Parser::StartParseInternal() { - ASSERT(!m_bHasParsed); - ASSERT(!m_bXRefTableRebuilt); + DCHECK(!m_bHasParsed); + DCHECK(!m_bXRefTableRebuilt); m_bHasParsed = true; m_bXRefStream = false; @@ -203,7 +295,7 @@ return eRet; } if (m_pSecurityHandler && !m_pSecurityHandler->IsMetadataEncrypted()) { - CPDF_Reference* pMetadata = + RetainPtr<const CPDF_Reference> pMetadata = ToReference(GetRoot()->GetObjectFor("Metadata")); if (pMetadata) m_MetadataObjnum = pMetadata->GetRefObjNum(); @@ -221,12 +313,12 @@ m_pSyntax->GetKeyword(); // Read XRef offset. - bool bNumber; - const ByteString xref_offset_str = m_pSyntax->GetNextWord(&bNumber); - if (!bNumber || xref_offset_str.IsEmpty()) + const CPDF_SyntaxParser::WordResult xref_offset_result = + m_pSyntax->GetNextWord(); + if (!xref_offset_result.is_number || xref_offset_result.word.IsEmpty()) return 0; - const FX_SAFE_FILESIZE result = FXSYS_atoi64(xref_offset_str.c_str()); + const FX_SAFE_FILESIZE result = FXSYS_atoi64(xref_offset_result.word.c_str()); if (!result.IsValid() || result.ValueOrDie() >= m_pSyntax->GetDocumentSize()) return 0; @@ -238,11 +330,11 @@ if (!GetTrailer()) return FORMAT_ERROR; - const CPDF_Dictionary* pEncryptDict = GetEncryptDict(); + RetainPtr<const CPDF_Dictionary> pEncryptDict = GetEncryptDict(); if (!pEncryptDict) return SUCCESS; - if (pEncryptDict->GetStringFor("Filter") != "Standard") + if (pEncryptDict->GetNameFor("Filter") != "Standard") return HANDLER_ERROR; auto pSecurityHandler = pdfium::MakeRetain<CPDF_SecurityHandler>(); @@ -263,16 +355,15 @@ // in the cross reference table are all off by one. bool CPDF_Parser::VerifyCrossRefV4() { for (const auto& it : m_CrossRefTable->objects_info()) { - if (it.second.pos == 0) + if (it.second.pos <= 0) continue; // Find the first non-zero position. FX_FILESIZE SavedPos = m_pSyntax->GetPos(); m_pSyntax->SetPos(it.second.pos); - bool is_num = false; - ByteString num_str = m_pSyntax->GetNextWord(&is_num); + CPDF_SyntaxParser::WordResult word_result = m_pSyntax->GetNextWord(); m_pSyntax->SetPos(SavedPos); - if (!is_num || num_str.IsEmpty() || - FXSYS_atoui(num_str.c_str()) != it.first) { + if (!word_result.is_number || word_result.word.IsEmpty() || + FXSYS_atoui(word_result.word.c_str()) != it.first) { // If the object number read doesn't match the one stored, // something is wrong with the cross reference table. return false; @@ -290,50 +381,50 @@ if (!trailer) return false; - m_CrossRefTable->SetTrailer(std::move(trailer)); - int32_t xrefsize = GetDirectInteger(GetTrailer(), "Size"); + m_CrossRefTable->SetTrailer(std::move(trailer), kNoV4TrailerObjectNumber); + const int32_t xrefsize = GetTrailer()->GetDirectIntegerFor("Size"); if (xrefsize > 0 && xrefsize <= kMaxXRefSize) ShrinkObjectMap(xrefsize); - std::vector<FX_FILESIZE> xref_stream_list{ - GetDirectInteger(GetTrailer(), "XRefStm")}; + FX_FILESIZE xref_stm = GetTrailer()->GetDirectIntegerFor("XRefStm"); + std::vector<FX_FILESIZE> xref_stream_list{xref_stm}; std::vector<FX_FILESIZE> xref_list{xref_offset}; std::set<FX_FILESIZE> seen_xref_offset{xref_offset}; // When the trailer doesn't have Prev entry or Prev entry value is not // numerical, GetDirectInteger() returns 0. Loading will end. - xref_offset = GetDirectInteger(GetTrailer(), "Prev"); - while (xref_offset) { + xref_offset = GetTrailer()->GetDirectIntegerFor("Prev"); + while (xref_offset > 0) { // Check for circular references. - if (pdfium::ContainsKey(seen_xref_offset, xref_offset)) + if (pdfium::Contains(seen_xref_offset, xref_offset)) return false; seen_xref_offset.insert(xref_offset); + xref_list.insert(xref_list.begin(), xref_offset); // SLOW ... - xref_list.insert(xref_list.begin(), xref_offset); LoadCrossRefV4(xref_offset, true); RetainPtr<CPDF_Dictionary> pDict(LoadTrailerV4()); if (!pDict) return false; - xref_offset = GetDirectInteger(pDict.Get(), "Prev"); + xref_offset = pDict->GetDirectIntegerFor("Prev"); + xref_stm = pDict->GetIntegerFor("XRefStm"); + xref_stream_list.insert(xref_stream_list.begin(), xref_stm); // SLOW ... - xref_stream_list.insert(xref_stream_list.begin(), - pDict->GetIntegerFor("XRefStm")); - m_CrossRefTable = CPDF_CrossRefTable::MergeUp( - pdfium::MakeUnique<CPDF_CrossRefTable>(std::move(pDict)), + std::make_unique<CPDF_CrossRefTable>(std::move(pDict), + kNoV4TrailerObjectNumber), std::move(m_CrossRefTable)); } for (size_t i = 0; i < xref_list.size(); ++i) { - if (!LoadCrossRefV4(xref_list[i], false)) + if (xref_list[i] > 0 && !LoadCrossRefV4(xref_list[i], false)) return false; - if (xref_stream_list[i] && !LoadCrossRefV5(&xref_stream_list[i], false)) + if (xref_stream_list[i] > 0 && !LoadCrossRefV5(&xref_stream_list[i], false)) return false; if (i == 0 && !VerifyCrossRefV4()) @@ -351,59 +442,60 @@ return false; // GetTrailer() currently returns the first-page trailer. - if (GetDirectInteger(GetTrailer(), "Size") == 0) + if (GetTrailer()->GetDirectIntegerFor("Size") == 0) return false; // Read /XRefStm from the first-page trailer. No need to read /Prev for the // first-page trailer, as the caller already did that and passed it in as // |main_xref_offset|. - std::vector<FX_FILESIZE> xref_stream_list{ - GetDirectInteger(GetTrailer(), "XRefStm")}; + FX_FILESIZE xref_stm = GetTrailer()->GetDirectIntegerFor("XRefStm"); + std::vector<FX_FILESIZE> xref_stream_list{xref_stm}; std::vector<FX_FILESIZE> xref_list{main_xref_offset}; std::set<FX_FILESIZE> seen_xref_offset{main_xref_offset}; // Merge the trailers. m_CrossRefTable = CPDF_CrossRefTable::MergeUp( - pdfium::MakeUnique<CPDF_CrossRefTable>(std::move(main_trailer)), + std::make_unique<CPDF_CrossRefTable>(std::move(main_trailer), + kNoV4TrailerObjectNumber), std::move(m_CrossRefTable)); // Now GetTrailer() returns the merged trailer, where /Prev is from the // main-trailer. - FX_FILESIZE xref_offset = GetDirectInteger(GetTrailer(), "Prev"); - while (xref_offset) { + FX_FILESIZE xref_offset = GetTrailer()->GetDirectIntegerFor("Prev"); + while (xref_offset > 0) { // Check for circular references. - if (pdfium::ContainsKey(seen_xref_offset, xref_offset)) + if (pdfium::Contains(seen_xref_offset, xref_offset)) return false; seen_xref_offset.insert(xref_offset); + xref_list.insert(xref_list.begin(), xref_offset); // SLOW ... - xref_list.insert(xref_list.begin(), xref_offset); LoadCrossRefV4(xref_offset, true); RetainPtr<CPDF_Dictionary> pDict(LoadTrailerV4()); if (!pDict) return false; - xref_offset = GetDirectInteger(pDict.Get(), "Prev"); + xref_offset = pDict->GetDirectIntegerFor("Prev"); + xref_stm = pDict->GetIntegerFor("XRefStm"); + xref_stream_list.insert(xref_stream_list.begin(), xref_stm); // SLOW ... - xref_stream_list.insert(xref_stream_list.begin(), - pDict->GetIntegerFor("XRefStm")); - m_CrossRefTable = CPDF_CrossRefTable::MergeUp( - pdfium::MakeUnique<CPDF_CrossRefTable>(std::move(pDict)), + std::make_unique<CPDF_CrossRefTable>(std::move(pDict), + kNoV4TrailerObjectNumber), std::move(m_CrossRefTable)); } - if (xref_stream_list[0] && !LoadCrossRefV5(&xref_stream_list[0], false)) + if (xref_stream_list[0] > 0 && !LoadCrossRefV5(&xref_stream_list[0], false)) return false; for (size_t i = 1; i < xref_list.size(); ++i) { - if (!LoadCrossRefV4(xref_list[i], false)) + if (xref_list[i] > 0 && !LoadCrossRefV4(xref_list[i], false)) return false; - if (xref_stream_list[i] && !LoadCrossRefV5(&xref_stream_list[i], false)) + if (xref_stream_list[i] > 0 && !LoadCrossRefV5(&xref_stream_list[i], false)) return false; } return true; @@ -419,11 +511,11 @@ // Each entry shall be exactly 20 byte. // A sample entry looks like: // "0000000000 00007 f\r\n" - static constexpr int32_t kEntryConstSize = 20; + static constexpr int32_t kEntrySize = 20; if (!out_objects) { FX_SAFE_FILESIZE pos = count; - pos *= kEntryConstSize; + pos *= kEntrySize; pos += m_pSyntax->GetPos(); if (!pos.IsValid()) return false; @@ -439,33 +531,32 @@ if (new_size.ValueOrDie() > kMaxXRefSize) return false; - const size_t max_entries_in_file = - m_pSyntax->GetDocumentSize() / kEntryConstSize; + const size_t max_entries_in_file = m_pSyntax->GetDocumentSize() / kEntrySize; if (new_size.ValueOrDie() > max_entries_in_file) return false; out_objects->resize(new_size.ValueOrDie()); - std::vector<char> buf(1024 * kEntryConstSize + 1); + DataVector<char> buf(1024 * kEntrySize + 1); buf.back() = '\0'; - uint32_t nBytesToRead = count; - while (nBytesToRead > 0) { - const uint32_t block_size = std::min(nBytesToRead, 1024u); - if (!m_pSyntax->ReadBlock(reinterpret_cast<uint8_t*>(buf.data()), - block_size * kEntryConstSize)) { + uint32_t entries_to_read = count; + while (entries_to_read > 0) { + const uint32_t entries_in_block = std::min(entries_to_read, 1024u); + const uint32_t bytes_to_read = entries_in_block * kEntrySize; + auto block_span = pdfium::make_span(buf).first(bytes_to_read); + if (!m_pSyntax->ReadBlock(pdfium::as_writable_bytes(block_span))) return false; - } - for (uint32_t i = 0; i < block_size; i++) { - uint32_t iObjectIndex = count - nBytesToRead + i; + for (uint32_t i = 0; i < entries_in_block; i++) { + uint32_t iObjectIndex = count - entries_to_read + i; CrossRefObjData& obj_data = (*out_objects)[start_obj_index + iObjectIndex]; const uint32_t objnum = start_objnum + iObjectIndex; obj_data.obj_num = objnum; ObjectInfo& info = obj_data.info; - char* pEntry = &buf[i * kEntryConstSize]; + const char* pEntry = &buf[i * kEntrySize]; if (pEntry[17] == 'f') { info.pos = 0; info.type = ObjectType::kFree; @@ -476,7 +567,7 @@ if (offset.ValueOrDie() == 0) { for (int32_t c = 0; c < 10; c++) { - if (!std::isdigit(pEntry[c])) + if (!isdigit(pEntry[c])) return false; } } @@ -490,7 +581,7 @@ info.type = ObjectType::kNotCompressed; } } - nBytesToRead -= block_size; + entries_to_read -= entries_in_block; } return true; } @@ -502,14 +593,14 @@ if (m_pSyntax->GetKeyword() != "xref") return false; std::vector<CrossRefObjData> result_objects; - while (1) { + while (true) { FX_FILESIZE saved_pos = m_pSyntax->GetPos(); - bool bIsNumber; - ByteString word = m_pSyntax->GetNextWord(&bIsNumber); + CPDF_SyntaxParser::WordResult word_result = m_pSyntax->GetNextWord(); + const ByteString& word = word_result.word; if (word.IsEmpty()) return false; - if (!bIsNumber) { + if (!word_result.is_number) { m_pSyntax->SetPos(saved_pos); break; } @@ -554,7 +645,8 @@ m_CrossRefTable->AddNormal(obj.obj_num, obj.info.gennum, obj.info.pos); break; case ObjectType::kCompressed: - m_CrossRefTable->AddCompressed(obj.obj_num, obj.info.archive_obj_num); + m_CrossRefTable->AddCompressed(obj.obj_num, obj.info.archive.obj_num, + obj.info.archive.obj_index); break; default: NOTREACHED(); @@ -567,13 +659,13 @@ return false; std::set<FX_FILESIZE> seen_xref_offset; - while (xref_offset) { + while (xref_offset > 0) { seen_xref_offset.insert(xref_offset); if (!LoadCrossRefV5(&xref_offset, false)) return false; // Check for circular references. - if (pdfium::ContainsKey(seen_xref_offset, xref_offset)) + if (pdfium::Contains(seen_xref_offset, xref_offset)) return false; } m_ObjectStreamMap.clear(); @@ -582,17 +674,17 @@ } bool CPDF_Parser::RebuildCrossRef() { - auto cross_ref_table = pdfium::MakeUnique<CPDF_CrossRefTable>(); + auto cross_ref_table = std::make_unique<CPDF_CrossRefTable>(); const uint32_t kBufferSize = 4096; m_pSyntax->SetReadBufferSize(kBufferSize); m_pSyntax->SetPos(0); - bool bIsNumber; std::vector<std::pair<uint32_t, FX_FILESIZE>> numbers; - for (ByteString word = m_pSyntax->GetNextWord(&bIsNumber); !word.IsEmpty(); - word = m_pSyntax->GetNextWord(&bIsNumber)) { - if (bIsNumber) { + for (CPDF_SyntaxParser::WordResult result = m_pSyntax->GetNextWord(); + !result.word.IsEmpty(); result = m_pSyntax->GetNextWord()) { + const ByteString& word = result.word; + if (result.is_number) { numbers.emplace_back(FXSYS_atoui(word.c_str()), m_pSyntax->GetPos() - word.GetLength()); if (numbers.size() > 2u) @@ -607,11 +699,17 @@ } else if (word == "trailer") { RetainPtr<CPDF_Object> pTrailer = m_pSyntax->GetObjectBody(nullptr); if (pTrailer) { + CPDF_Stream* stream_trailer = pTrailer->AsMutableStream(); + // Grab the object number from `pTrailer` before potentially calling + // std::move(pTrailer) below. + const uint32_t trailer_object_number = pTrailer->GetObjNum(); + RetainPtr<CPDF_Dictionary> trailer_dict = + stream_trailer ? stream_trailer->GetMutableDict() + : ToDictionary(std::move(pTrailer)); cross_ref_table = CPDF_CrossRefTable::MergeUp( std::move(cross_ref_table), - pdfium::MakeUnique<CPDF_CrossRefTable>(ToDictionary( - pTrailer->IsStream() ? pTrailer->AsStream()->GetDict()->Clone() - : std::move(pTrailer)))); + std::make_unique<CPDF_CrossRefTable>(std::move(trailer_dict), + trailer_object_number)); } } else if (word == "obj" && numbers.size() == 2u) { const FX_FILESIZE obj_pos = numbers[0].second; @@ -623,20 +721,24 @@ ToStream(m_pSyntax->GetIndirectObject( nullptr, CPDF_SyntaxParser::ParseType::kStrict)); - if (pStream && pStream->GetDict()->GetStringFor("Type") == "XRef") { + if (pStream && pStream->GetDict()->GetNameFor("Type") == "XRef") { cross_ref_table = CPDF_CrossRefTable::MergeUp( std::move(cross_ref_table), - pdfium::MakeUnique<CPDF_CrossRefTable>( - ToDictionary(pStream->GetDict()->Clone()))); + std::make_unique<CPDF_CrossRefTable>( + ToDictionary(pStream->GetDict()->Clone()), + pStream->GetObjNum())); } if (obj_num < kMaxObjectNumber) { cross_ref_table->AddNormal(obj_num, gen_num, obj_pos); - if (const auto object_stream = - CPDF_ObjectStream::Create(pStream.Get())) { - for (const auto& it : object_stream->objects_offsets()) { - if (it.first < kMaxObjectNumber) - cross_ref_table->AddCompressed(it.first, obj_num); + const auto object_stream = + CPDF_ObjectStream::Create(std::move(pStream)); + if (object_stream) { + const auto& object_info = object_stream->object_info(); + for (size_t i = 0; i < object_info.size(); ++i) { + const auto& info = object_info[i]; + if (info.obj_num < kMaxObjectNumber) + cross_ref_table->AddCompressed(info.obj_num, obj_num, i); } } } @@ -657,161 +759,153 @@ if (!pObject || !pObject->GetObjNum()) return false; - CPDF_Stream* pStream = pObject->AsStream(); + RetainPtr<const CPDF_Stream> pStream(pObject->AsStream()); if (!pStream) return false; - CPDF_Dictionary* pDict = pStream->GetDict(); - *pos = pDict->GetIntegerFor("Prev"); + RetainPtr<const CPDF_Dictionary> pDict = pStream->GetDict(); + int32_t prev = pDict->GetIntegerFor("Prev"); + if (prev < 0) + return false; + int32_t size = pDict->GetIntegerFor("Size"); if (size < 0) return false; + *pos = prev; + RetainPtr<CPDF_Dictionary> pNewTrailer = ToDictionary(pDict->Clone()); if (bMainXRef) { - m_CrossRefTable = - pdfium::MakeUnique<CPDF_CrossRefTable>(std::move(pNewTrailer)); + m_CrossRefTable = std::make_unique<CPDF_CrossRefTable>( + std::move(pNewTrailer), pStream->GetObjNum()); m_CrossRefTable->ShrinkObjectMap(size); } else { m_CrossRefTable = CPDF_CrossRefTable::MergeUp( - pdfium::MakeUnique<CPDF_CrossRefTable>(std::move(pNewTrailer)), + std::make_unique<CPDF_CrossRefTable>(std::move(pNewTrailer), + pStream->GetObjNum()), std::move(m_CrossRefTable)); } - std::vector<std::pair<int32_t, int32_t>> arrIndex; - CPDF_Array* pArray = pDict->GetArrayFor("Index"); - if (pArray) { - for (size_t i = 0; i < pArray->size() / 2; i++) { - CPDF_Object* pStartNumObj = pArray->GetObjectAt(i * 2); - CPDF_Object* pCountObj = pArray->GetObjectAt(i * 2 + 1); + std::vector<CrossRefV5IndexEntry> indices = + GetCrossRefV5Indices(pDict->GetArrayFor("Index").Get(), size); - if (ToNumber(pStartNumObj) && ToNumber(pCountObj)) { - int nStartNum = pStartNumObj->GetInteger(); - int nCount = pCountObj->GetInteger(); - if (nStartNum >= 0 && nCount > 0) - arrIndex.push_back(std::make_pair(nStartNum, nCount)); - } - } - } - - if (arrIndex.empty()) - arrIndex.push_back(std::make_pair(0, size)); - - pArray = pDict->GetArrayFor("W"); - if (!pArray) + std::vector<uint32_t> field_widths = + GetFieldWidths(pDict->GetArrayFor("W").Get()); + if (field_widths.size() < kMinFieldCount) return false; - std::vector<uint32_t> WidthArray; - FX_SAFE_UINT32 dwAccWidth = 0; - for (size_t i = 0; i < pArray->size(); ++i) { - WidthArray.push_back(pArray->GetIntegerAt(i)); - dwAccWidth += WidthArray[i]; - } - - if (!dwAccWidth.IsValid() || WidthArray.size() < 3) + FX_SAFE_UINT32 dwAccWidth; + for (uint32_t width : field_widths) + dwAccWidth += width; + if (!dwAccWidth.IsValid()) return false; - uint32_t totalWidth = dwAccWidth.ValueOrDie(); - auto pAcc = pdfium::MakeRetain<CPDF_StreamAcc>(pStream); + uint32_t total_width = dwAccWidth.ValueOrDie(); + auto pAcc = pdfium::MakeRetain<CPDF_StreamAcc>(std::move(pStream)); pAcc->LoadAllDataFiltered(); - const uint8_t* pData = pAcc->GetData(); - uint32_t dwTotalSize = pAcc->GetSize(); + pdfium::span<const uint8_t> data_span = pAcc->GetSpan(); uint32_t segindex = 0; - for (const auto& index : arrIndex) { - const int32_t startnum = index.first; - if (startnum < 0) + for (const auto& index : indices) { + FX_SAFE_UINT32 seg_end = segindex; + seg_end += index.obj_count; + seg_end *= total_width; + if (!seg_end.IsValid() || seg_end.ValueOrDie() > data_span.size()) continue; - uint32_t count = pdfium::base::checked_cast<uint32_t>(index.second); - FX_SAFE_UINT32 dwCaculatedSize = segindex; - dwCaculatedSize += count; - dwCaculatedSize *= totalWidth; - if (!dwCaculatedSize.IsValid() || - dwCaculatedSize.ValueOrDie() > dwTotalSize) { - continue; - } - - const uint8_t* segstart = pData + segindex * totalWidth; - FX_SAFE_UINT32 dwMaxObjNum = startnum; - dwMaxObjNum += count; + pdfium::span<const uint8_t> seg_span = data_span.subspan( + segindex * total_width, index.obj_count * total_width); + FX_SAFE_UINT32 dwMaxObjNum = index.start_obj_num; + dwMaxObjNum += index.obj_count; uint32_t dwV5Size = m_CrossRefTable->objects_info().empty() ? 0 : GetLastObjNum() + 1; if (!dwMaxObjNum.IsValid() || dwMaxObjNum.ValueOrDie() > dwV5Size) continue; - for (uint32_t i = 0; i < count; i++) { - ObjectType type = ObjectType::kNotCompressed; - const uint8_t* entrystart = segstart + i * totalWidth; - if (WidthArray[0]) { - const uint32_t cross_ref_stream_obj_type = - GetVarInt(entrystart, WidthArray[0]); - type = GetObjectTypeFromCrossRefStreamType(cross_ref_stream_obj_type); - if (type == ObjectType::kNull) - continue; - } + for (uint32_t i = 0; i < index.obj_count; ++i) { + const uint32_t obj_num = index.start_obj_num + i; + if (obj_num >= CPDF_Parser::kMaxObjectNumber) + break; - const uint32_t objnum = startnum + i; - if (objnum >= CPDF_Parser::kMaxObjectNumber) - continue; - - const ObjectType existing_type = GetObjectType(objnum); - if (existing_type == ObjectType::kNull) { - uint32_t offset = GetVarInt(entrystart + WidthArray[0], WidthArray[1]); - if (pdfium::base::IsValueInRangeForNumericType<FX_FILESIZE>(offset)) - m_CrossRefTable->AddNormal(objnum, 0, offset); - continue; - } - - if (existing_type != ObjectType::kFree) - continue; - - if (type == ObjectType::kFree) { - m_CrossRefTable->SetFree(objnum); - continue; - } - - const uint32_t entry_value = - GetVarInt(entrystart + WidthArray[0], WidthArray[1]); - if (type == ObjectType::kNotCompressed) { - const uint32_t offset = entry_value; - if (pdfium::base::IsValueInRangeForNumericType<FX_FILESIZE>(offset)) - m_CrossRefTable->AddNormal(objnum, 0, offset); - continue; - } - - ASSERT(type == ObjectType::kCompressed); - const uint32_t archive_obj_num = entry_value; - if (!IsValidObjectNumber(archive_obj_num)) - return false; - - m_CrossRefTable->AddCompressed(objnum, archive_obj_num); + ProcessCrossRefV5Entry(seg_span.subspan(i * total_width, total_width), + field_widths, obj_num); } - segindex += count; + + segindex += index.obj_count; } return true; } -const CPDF_Array* CPDF_Parser::GetIDArray() const { +void CPDF_Parser::ProcessCrossRefV5Entry( + pdfium::span<const uint8_t> entry_span, + pdfium::span<const uint32_t> field_widths, + uint32_t obj_num) { + DCHECK_GE(field_widths.size(), kMinFieldCount); + ObjectType type = ObjectType::kNotCompressed; + if (field_widths[0]) { + const uint32_t cross_ref_stream_obj_type = + GetFirstXRefStreamEntry(entry_span, field_widths); + type = GetObjectTypeFromCrossRefStreamType(cross_ref_stream_obj_type); + if (type == ObjectType::kNull) + return; + } + + const ObjectType existing_type = GetObjectType(obj_num); + if (existing_type == ObjectType::kNull) { + const uint32_t offset = GetSecondXRefStreamEntry(entry_span, field_widths); + if (pdfium::base::IsValueInRangeForNumericType<FX_FILESIZE>(offset)) + m_CrossRefTable->AddNormal(obj_num, 0, offset); + return; + } + + if (existing_type != ObjectType::kFree) + return; + + if (type == ObjectType::kFree) { + m_CrossRefTable->SetFree(obj_num); + return; + } + + if (type == ObjectType::kNotCompressed) { + const uint32_t offset = GetSecondXRefStreamEntry(entry_span, field_widths); + if (pdfium::base::IsValueInRangeForNumericType<FX_FILESIZE>(offset)) + m_CrossRefTable->AddNormal(obj_num, 0, offset); + return; + } + + DCHECK_EQ(type, ObjectType::kCompressed); + const uint32_t archive_obj_num = + GetSecondXRefStreamEntry(entry_span, field_widths); + if (!IsValidObjectNumber(archive_obj_num)) { + return; + } + + const uint32_t archive_obj_index = + GetThirdXRefStreamEntry(entry_span, field_widths); + m_CrossRefTable->AddCompressed(obj_num, archive_obj_num, archive_obj_index); +} + +RetainPtr<const CPDF_Array> CPDF_Parser::GetIDArray() const { return GetTrailer() ? GetTrailer()->GetArrayFor("ID") : nullptr; } -CPDF_Dictionary* CPDF_Parser::GetRoot() const { - CPDF_Object* obj = +RetainPtr<const CPDF_Dictionary> CPDF_Parser::GetRoot() const { + RetainPtr<CPDF_Object> obj = m_pObjectsHolder->GetOrParseIndirectObject(GetRootObjNum()); return obj ? obj->GetDict() : nullptr; } -const CPDF_Dictionary* CPDF_Parser::GetEncryptDict() const { +RetainPtr<const CPDF_Dictionary> CPDF_Parser::GetEncryptDict() const { if (!GetTrailer()) return nullptr; - const CPDF_Object* pEncryptObj = GetTrailer()->GetObjectFor("Encrypt"); + RetainPtr<const CPDF_Object> pEncryptObj = + GetTrailer()->GetObjectFor("Encrypt"); if (!pEncryptObj) return nullptr; if (pEncryptObj->IsDictionary()) - return ToDictionary(pEncryptObj); + return pdfium::WrapRetain(pEncryptObj->AsDictionary()); if (pEncryptObj->IsReference()) { return ToDictionary(m_pObjectsHolder->GetOrParseIndirectObject( @@ -832,6 +926,10 @@ return m_CrossRefTable->GetMutableTrailerForTesting(); } +uint32_t CPDF_Parser::GetTrailerObjectNumber() const { + return m_CrossRefTable->trailer_object_number(); +} + RetainPtr<CPDF_Dictionary> CPDF_Parser::GetCombinedTrailer() const { return m_CrossRefTable->trailer() ? ToDictionary(m_CrossRefTable->trailer()->Clone()) @@ -839,7 +937,7 @@ } uint32_t CPDF_Parser::GetInfoObjNum() const { - const CPDF_Reference* pRef = + RetainPtr<const CPDF_Reference> pRef = ToReference(m_CrossRefTable->trailer() ? m_CrossRefTable->trailer()->GetObjectFor("Info") : nullptr); @@ -847,7 +945,7 @@ } uint32_t CPDF_Parser::GetRootObjNum() const { - const CPDF_Reference* pRef = + RetainPtr<const CPDF_Reference> pRef = ToReference(m_CrossRefTable->trailer() ? m_CrossRefTable->trailer()->GetObjectFor("Root") : nullptr); @@ -859,10 +957,10 @@ return nullptr; // Prevent circular parsing the same object. - if (pdfium::ContainsKey(m_ParsingObjNums, objnum)) + if (pdfium::Contains(m_ParsingObjNums, objnum)) return nullptr; - pdfium::ScopedSetInsertion<uint32_t> local_insert(&m_ParsingObjNums, objnum); + ScopedSetInsertion<uint32_t> local_insert(&m_ParsingObjNums, objnum); if (GetObjectType(objnum) == ObjectType::kNotCompressed) { FX_FILESIZE pos = GetObjectPositionOrZero(objnum); if (pos <= 0) @@ -872,22 +970,20 @@ if (GetObjectType(objnum) != ObjectType::kCompressed) return nullptr; - const CPDF_ObjectStream* pObjStream = - GetObjectStream(m_CrossRefTable->GetObjectInfo(objnum)->archive_obj_num); + const ObjectInfo& info = *m_CrossRefTable->GetObjectInfo(objnum); + const CPDF_ObjectStream* pObjStream = GetObjectStream(info.archive.obj_num); if (!pObjStream) return nullptr; - return pObjStream->ParseObject(m_pObjectsHolder.Get(), objnum); + return pObjStream->ParseObject(m_pObjectsHolder, objnum, + info.archive.obj_index); } const CPDF_ObjectStream* CPDF_Parser::GetObjectStream(uint32_t object_number) { // Prevent circular parsing the same object. - if (pdfium::ContainsKey(m_ParsingObjNums, object_number)) + if (pdfium::Contains(m_ParsingObjNums, object_number)) return nullptr; - pdfium::ScopedSetInsertion<uint32_t> local_insert(&m_ParsingObjNums, - object_number); - auto it = m_ObjectStreamMap.find(object_number); if (it != m_ObjectStreamMap.end()) return it->second.get(); @@ -900,13 +996,16 @@ if (object_pos <= 0) return nullptr; + // Keep track of `object_number` before doing more parsing. + ScopedSetInsertion<uint32_t> local_insert(&m_ParsingObjNums, object_number); + RetainPtr<CPDF_Object> object = ParseIndirectObjectAt(object_pos, object_number); if (!object) return nullptr; std::unique_ptr<CPDF_ObjectStream> objs_stream = - CPDF_ObjectStream::Create(ToStream(object.Get())); + CPDF_ObjectStream::Create(ToStream(object)); const CPDF_ObjectStream* result = objs_stream.get(); m_ObjectStreamMap[object_number] = std::move(objs_stream); @@ -919,7 +1018,7 @@ m_pSyntax->SetPos(pos); auto result = m_pSyntax->GetIndirectObject( - m_pObjectsHolder.Get(), CPDF_SyntaxParser::ParseType::kLoose); + m_pObjectsHolder, CPDF_SyntaxParser::ParseType::kLoose); m_pSyntax->SetPos(saved_pos); if (result && objnum && result->GetObjNum() != objnum) return nullptr; @@ -934,11 +1033,15 @@ return result; } +FX_FILESIZE CPDF_Parser::GetDocumentSize() const { + return m_pSyntax->GetDocumentSize(); +} + uint32_t CPDF_Parser::GetFirstPageNo() const { return m_pLinearized ? m_pLinearized->GetFirstPageNo() : 0; } -void CPDF_Parser::SetLinearizedHeader( +void CPDF_Parser::SetLinearizedHeaderForTesting( std::unique_ptr<CPDF_LinearizedHeader> pLinearized) { m_pLinearized = std::move(pLinearized); } @@ -947,7 +1050,7 @@ if (m_pSyntax->GetKeyword() != "trailer") return nullptr; - return ToDictionary(m_pSyntax->GetObjectBody(m_pObjectsHolder.Get())); + return ToDictionary(m_pSyntax->GetObjectBody(m_pObjectsHolder)); } uint32_t CPDF_Parser::GetPermissions() const { @@ -959,15 +1062,15 @@ } CPDF_Parser::Error CPDF_Parser::StartLinearizedParse( - const RetainPtr<CPDF_ReadValidator>& validator, - const char* password) { - ASSERT(!m_bHasParsed); - ASSERT(!m_bXRefTableRebuilt); + RetainPtr<CPDF_ReadValidator> validator, + const ByteString& password) { + DCHECK(!m_bHasParsed); + DCHECK(!m_bXRefTableRebuilt); SetPassword(password); m_bXRefStream = false; m_LastXRefOffset = 0; - if (!InitSyntaxParser(validator)) + if (!InitSyntaxParser(std::move(validator))) return FORMAT_ERROR; m_pLinearized = ParseLinearizedHeader(); @@ -991,10 +1094,16 @@ if (!trailer) return SUCCESS; - m_CrossRefTable->SetTrailer(std::move(trailer)); - int32_t xrefsize = GetDirectInteger(GetTrailer(), "Size"); - if (xrefsize > 0) - ShrinkObjectMap(xrefsize); + m_CrossRefTable->SetTrailer(std::move(trailer), kNoV4TrailerObjectNumber); + const int32_t xrefsize = GetTrailer()->GetDirectIntegerFor("Size"); + if (xrefsize > 0) { + // Check if `xrefsize` is correct. If it is incorrect, give up and rebuild + // the xref table. + const uint32_t expected_last_obj_num = xrefsize - 1; + if (GetLastObjNum() != expected_last_obj_num && !RebuildCrossRef()) { + return FORMAT_ERROR; + } + } } Error eRet = SetEncryptHandler(); @@ -1029,8 +1138,9 @@ } if (m_pSecurityHandler && m_pSecurityHandler->IsMetadataEncrypted()) { - if (CPDF_Reference* pMetadata = - ToReference(GetRoot()->GetObjectFor("Metadata"))) + RetainPtr<const CPDF_Reference> pMetadata = + ToReference(GetRoot()->GetObjectFor("Metadata")); + if (pMetadata) m_MetadataObjnum = pMetadata->GetRefObjNum(); } return SUCCESS; @@ -1048,7 +1158,7 @@ return false; // Check for circular references. - if (pdfium::ContainsKey(seen_xref_offset, xref_offset)) + if (pdfium::Contains(seen_xref_offset, xref_offset)) return false; } m_ObjectStreamMap.clear(); @@ -1078,16 +1188,69 @@ return SUCCESS; } -CPDF_Parser::ObjectType CPDF_Parser::GetObjectTypeFromCrossRefStreamType( - uint32_t cross_ref_stream_type) const { - switch (cross_ref_stream_type) { - case 0: - return CPDF_Parser::ObjectType::kFree; - case 1: - return CPDF_Parser::ObjectType::kNotCompressed; - case 2: - return CPDF_Parser::ObjectType::kCompressed; - default: - return CPDF_Parser::ObjectType::kNull; +void CPDF_Parser::SetSyntaxParserForTesting( + std::unique_ptr<CPDF_SyntaxParser> parser) { + m_pSyntax = std::move(parser); +} + +std::vector<unsigned int> CPDF_Parser::GetTrailerEnds() { + std::vector<unsigned int> trailer_ends; + m_pSyntax->SetTrailerEnds(&trailer_ends); + + // Traverse the document. + m_pSyntax->SetPos(0); + while (true) { + CPDF_SyntaxParser::WordResult word_result = m_pSyntax->GetNextWord(); + if (word_result.is_number) { + // The object number was read. Read the generation number. + word_result = m_pSyntax->GetNextWord(); + if (!word_result.is_number) + break; + + word_result = m_pSyntax->GetNextWord(); + if (word_result.word != "obj") + break; + + m_pSyntax->GetObjectBody(nullptr); + + word_result = m_pSyntax->GetNextWord(); + if (word_result.word != "endobj") + break; + } else if (word_result.word == "trailer") { + m_pSyntax->GetObjectBody(nullptr); + } else if (word_result.word == "startxref") { + m_pSyntax->GetNextWord(); + } else if (word_result.word == "xref") { + while (true) { + word_result = m_pSyntax->GetNextWord(); + if (word_result.word.IsEmpty() || word_result.word == "startxref") + break; + } + m_pSyntax->GetNextWord(); + } else { + break; + } } + + // Stop recording trailer ends. + m_pSyntax->SetTrailerEnds(nullptr); + return trailer_ends; +} + +bool CPDF_Parser::WriteToArchive(IFX_ArchiveStream* archive, + FX_FILESIZE src_size) { + static constexpr FX_FILESIZE kBufferSize = 4096; + DataVector<uint8_t> buffer(kBufferSize); + m_pSyntax->SetPos(0); + while (src_size) { + const uint32_t block_size = + static_cast<uint32_t>(std::min(kBufferSize, src_size)); + auto block_span = pdfium::make_span(buffer).first(block_size); + if (!m_pSyntax->ReadBlock(block_span)) + return false; + if (!archive->WriteBlock(pdfium::make_span(buffer).first(block_size))) + return false; + src_size -= block_size; + } + return true; }
diff --git a/core/fpdfapi/parser/cpdf_parser.h b/core/fpdfapi/parser/cpdf_parser.h index d44244a..21dd8aa 100644 --- a/core/fpdfapi/parser/cpdf_parser.h +++ b/core/fpdfapi/parser/cpdf_parser.h
@@ -1,4 +1,4 @@ -// Copyright 2016 PDFium Authors. All rights reserved. +// Copyright 2016 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -7,6 +7,9 @@ #ifndef CORE_FPDFAPI_PARSER_CPDF_PARSER_H_ #define CORE_FPDFAPI_PARSER_CPDF_PARSER_H_ +#include <stddef.h> +#include <stdint.h> + #include <limits> #include <map> #include <memory> @@ -15,13 +18,12 @@ #include "core/fpdfapi/parser/cpdf_cross_ref_table.h" #include "core/fpdfapi/parser/cpdf_indirect_object_holder.h" -#include "core/fxcrt/fx_string.h" -#include "core/fxcrt/fx_system.h" +#include "core/fxcrt/bytestring.h" +#include "core/fxcrt/fx_types.h" #include "core/fxcrt/retain_ptr.h" #include "core/fxcrt/unowned_ptr.h" class CPDF_Array; -class CPDF_CryptoHandler; class CPDF_Dictionary; class CPDF_LinearizedHeader; class CPDF_Object; @@ -29,10 +31,14 @@ class CPDF_ReadValidator; class CPDF_SecurityHandler; class CPDF_SyntaxParser; +class IFX_ArchiveStream; class IFX_SeekableReadStream; class CPDF_Parser { public: + using ObjectType = CPDF_CrossRefTable::ObjectType; + using ObjectInfo = CPDF_CrossRefTable::ObjectInfo; + class ParsedObjectsHolder : public CPDF_IndirectObjectHolder { public: virtual bool TryInit() = 0; @@ -53,18 +59,18 @@ // are non-consecutive. static constexpr uint32_t kMaxObjectNumber = 4 * 1024 * 1024; - static const size_t kInvalidPos = std::numeric_limits<size_t>::max(); + static constexpr size_t kInvalidPos = std::numeric_limits<size_t>::max(); explicit CPDF_Parser(ParsedObjectsHolder* holder); CPDF_Parser(); ~CPDF_Parser(); - Error StartParse(const RetainPtr<IFX_SeekableReadStream>& pFile, - const char* password); - Error StartLinearizedParse(const RetainPtr<CPDF_ReadValidator>& validator, - const char* password); + Error StartParse(RetainPtr<IFX_SeekableReadStream> pFile, + const ByteString& password); + Error StartLinearizedParse(RetainPtr<CPDF_ReadValidator> validator, + const ByteString& password); - void SetPassword(const char* password) { m_Password = password; } + void SetPassword(const ByteString& password) { m_Password = password; } ByteString GetPassword() const { return m_Password; } // Take the GetPassword() value and encode it, if necessary, based on the @@ -73,6 +79,7 @@ const CPDF_Dictionary* GetTrailer() const; CPDF_Dictionary* GetMutableTrailerForTesting(); + uint32_t GetTrailerObjectNumber() const; // Returns a new trailer which combines the last read trailer with the /Root // and /Info from previous ones. @@ -83,10 +90,9 @@ uint32_t GetPermissions() const; uint32_t GetRootObjNum() const; uint32_t GetInfoObjNum() const; - const CPDF_Array* GetIDArray() const; - CPDF_Dictionary* GetRoot() const; - - const CPDF_Dictionary* GetEncryptDict() const; + RetainPtr<const CPDF_Array> GetIDArray() const; + RetainPtr<const CPDF_Dictionary> GetRoot() const; + RetainPtr<const CPDF_Dictionary> GetEncryptDict() const; RetainPtr<CPDF_Object> ParseIndirectObject(uint32_t objnum); @@ -105,6 +111,7 @@ RetainPtr<CPDF_Object> ParseIndirectObjectAt(FX_FILESIZE pos, uint32_t objnum); + FX_FILESIZE GetDocumentSize() const; uint32_t GetFirstPageNo() const; const CPDF_LinearizedHeader* GetLinearizedHeader() const { return m_pLinearized.get(); @@ -116,24 +123,22 @@ bool xref_table_rebuilt() const { return m_bXRefTableRebuilt; } - CPDF_SyntaxParser* GetSyntax() const { return m_pSyntax.get(); } + std::vector<unsigned int> GetTrailerEnds(); + bool WriteToArchive(IFX_ArchiveStream* archive, FX_FILESIZE src_size); - void SetLinearizedHeader(std::unique_ptr<CPDF_LinearizedHeader> pLinearized); + void SetLinearizedHeaderForTesting( + std::unique_ptr<CPDF_LinearizedHeader> pLinearized); protected: - using ObjectType = CPDF_CrossRefTable::ObjectType; - using ObjectInfo = CPDF_CrossRefTable::ObjectInfo; - bool LoadCrossRefV4(FX_FILESIZE pos, bool bSkip); bool RebuildCrossRef(); + Error StartParseInternal(); + FX_FILESIZE ParseStartXRef(); + std::unique_ptr<CPDF_LinearizedHeader> ParseLinearizedHeader(); - std::unique_ptr<CPDF_SyntaxParser> m_pSyntax; + void SetSyntaxParserForTesting(std::unique_ptr<CPDF_SyntaxParser> parser); private: - friend class cpdf_parser_BadStartXrefShouldNotBuildCrossRefTable_Test; - friend class cpdf_parser_ParseStartXRefWithHeaderOffset_Test; - friend class cpdf_parser_ParseStartXRef_Test; - friend class cpdf_parser_ParseLinearizedWithHeaderOffset_Test; friend class CPDF_DataAvail; struct CrossRefObjData { @@ -141,11 +146,12 @@ ObjectInfo info; }; - Error StartParseInternal(); - FX_FILESIZE ParseStartXRef(); bool LoadAllCrossRefV4(FX_FILESIZE xref_offset); bool LoadAllCrossRefV5(FX_FILESIZE xref_offset); bool LoadCrossRefV5(FX_FILESIZE* pos, bool bMainXRef); + void ProcessCrossRefV5Entry(pdfium::span<const uint8_t> entry_span, + pdfium::span<const uint32_t> field_widths, + uint32_t obj_num); RetainPtr<CPDF_Dictionary> LoadTrailerV4(); Error SetEncryptHandler(); void ReleaseEncryptHandler(); @@ -153,7 +159,6 @@ bool LoadLinearizedAllCrossRefV5(FX_FILESIZE main_xref_offset); Error LoadLinearizedMainXRefTable(); const CPDF_ObjectStream* GetObjectStream(uint32_t object_number); - std::unique_ptr<CPDF_LinearizedHeader> ParseLinearizedHeader(); void ShrinkObjectMap(uint32_t size); // A simple check whether the cross reference table matches with // the objects. @@ -168,13 +173,12 @@ bool ParseCrossRefV4(std::vector<CrossRefObjData>* out_objects); void MergeCrossRefObjectsData(const std::vector<CrossRefObjData>& objects); - bool InitSyntaxParser(const RetainPtr<CPDF_ReadValidator>& validator); + bool InitSyntaxParser(RetainPtr<CPDF_ReadValidator> validator); bool ParseFileVersion(); ObjectType GetObjectType(uint32_t objnum) const; - ObjectType GetObjectTypeFromCrossRefStreamType( - uint32_t cross_ref_stream_type) const; + std::unique_ptr<CPDF_SyntaxParser> m_pSyntax; std::unique_ptr<ParsedObjectsHolder> m_pOwnedObjectsHolder; UnownedPtr<ParsedObjectsHolder> m_pObjectsHolder; @@ -182,11 +186,11 @@ bool m_bXRefStream = false; bool m_bXRefTableRebuilt = false; int m_FileVersion = 0; + uint32_t m_MetadataObjnum = 0; // m_CrossRefTable must be destroyed after m_pSecurityHandler due to the // ownership of the ID array data. std::unique_ptr<CPDF_CrossRefTable> m_CrossRefTable; - FX_FILESIZE m_LastXRefOffset; - RetainPtr<CPDF_SecurityHandler> m_pSecurityHandler; + FX_FILESIZE m_LastXRefOffset = 0; ByteString m_Password; std::unique_ptr<CPDF_LinearizedHeader> m_pLinearized; @@ -196,7 +200,7 @@ // All indirect object numbers that are being parsed. std::set<uint32_t> m_ParsingObjNums; - uint32_t m_MetadataObjnum = 0; + RetainPtr<CPDF_SecurityHandler> m_pSecurityHandler; }; #endif // CORE_FPDFAPI_PARSER_CPDF_PARSER_H_
diff --git a/core/fpdfapi/parser/cpdf_parser_embeddertest.cpp b/core/fpdfapi/parser/cpdf_parser_embeddertest.cpp index 9294534..17ac00f 100644 --- a/core/fpdfapi/parser/cpdf_parser_embeddertest.cpp +++ b/core/fpdfapi/parser/cpdf_parser_embeddertest.cpp
@@ -1,4 +1,4 @@ -// Copyright 2015 PDFium Authors. All rights reserved. +// Copyright 2015 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -8,45 +8,45 @@ class CPDFParserEmbedderTest : public EmbedderTest {}; -TEST_F(CPDFParserEmbedderTest, LoadError_454695) { +TEST_F(CPDFParserEmbedderTest, LoadErrorBug454695) { // Test a dictionary with hex string instead of correct content. // Verify that the defective pdf shouldn't be opened correctly. EXPECT_FALSE(OpenDocument("bug_454695.pdf")); } -TEST_F(CPDFParserEmbedderTest, Bug_481363) { +TEST_F(CPDFParserEmbedderTest, Bug481363) { // Test colorspace object with malformed dictionary. - EXPECT_TRUE(OpenDocument("bug_481363.pdf")); + ASSERT_TRUE(OpenDocument("bug_481363.pdf")); FPDF_PAGE page = LoadPage(0); - EXPECT_NE(nullptr, page); + EXPECT_TRUE(page); UnloadPage(page); } -TEST_F(CPDFParserEmbedderTest, Bug_544880) { +TEST_F(CPDFParserEmbedderTest, Bug544880) { // Test self referencing /Pages object. - EXPECT_TRUE(OpenDocument("bug_544880.pdf")); + ASSERT_TRUE(OpenDocument("bug_544880.pdf")); // Shouldn't crash. We don't check the return value here because we get the // the count from the "/Count 1" in the testcase (at the time of writing) // rather than the actual count (0). (void)GetPageCount(); } -TEST_F(CPDFParserEmbedderTest, Bug_325a) { +TEST_F(CPDFParserEmbedderTest, Bug325a) { EXPECT_FALSE(OpenDocument("bug_325_a.pdf")); } -TEST_F(CPDFParserEmbedderTest, Bug_325b) { +TEST_F(CPDFParserEmbedderTest, Bug325b) { EXPECT_FALSE(OpenDocument("bug_325_b.pdf")); } -TEST_F(CPDFParserEmbedderTest, Bug_602650) { +TEST_F(CPDFParserEmbedderTest, Bug602650) { // Test the case that cross reference entries, which are well formed, // but do not match with the objects. - EXPECT_TRUE(OpenDocument("bug_602650.pdf")); + ASSERT_TRUE(OpenDocument("bug_602650.pdf")); FPDF_PAGE page = LoadPage(0); - EXPECT_NE(nullptr, page); + EXPECT_TRUE(page); FPDF_TEXTPAGE text_page = FPDFText_LoadPage(page); - EXPECT_NE(nullptr, text_page); + EXPECT_TRUE(text_page); // The page should not be blank. EXPECT_LT(0, FPDFText_CountChars(text_page)); @@ -54,29 +54,34 @@ UnloadPage(page); } -TEST_F(CPDFParserEmbedderTest, Bug_757705) { - EXPECT_TRUE(OpenDocument("bug_757705.pdf")); +TEST_F(CPDFParserEmbedderTest, Bug757705) { + ASSERT_TRUE(OpenDocument("bug_757705.pdf")); } TEST_F(CPDFParserEmbedderTest, LoadMainCrossRefTable) { - EXPECT_TRUE(OpenDocumentLinearized("feature_linearized_loading.pdf")); + ASSERT_TRUE(OpenDocumentLinearized("feature_linearized_loading.pdf")); // To check that main cross ref table is loaded correctly,will be enough to // check that the second page was correctly loaded. Because it is contains // crossrefs for second page. EXPECT_EQ(2, GetPageCount()); FPDF_PAGE page = LoadPage(1); - EXPECT_NE(nullptr, page); + EXPECT_TRUE(page); FPDF_TEXTPAGE text_page = FPDFText_LoadPage(page); - EXPECT_NE(nullptr, text_page); + EXPECT_TRUE(text_page); // The page should not be blank. EXPECT_LT(0, FPDFText_CountChars(text_page)); FPDFText_ClosePage(text_page); UnloadPage(page); } -TEST_F(CPDFParserEmbedderTest, Bug_828049) { - EXPECT_TRUE(OpenDocument("bug_828049.pdf")); +TEST_F(CPDFParserEmbedderTest, Bug828049) { + ASSERT_TRUE(OpenDocument("bug_828049.pdf")); FPDF_PAGE page = LoadPage(0); - EXPECT_NE(nullptr, page); + EXPECT_TRUE(page); UnloadPage(page); } + +// crbug.com/1191313 +TEST_F(CPDFParserEmbedderTest, InvalidDictionaryKeys) { + ASSERT_TRUE(OpenDocument("bad_dict_keys.pdf")); +}
diff --git a/core/fpdfapi/parser/cpdf_parser_unittest.cpp b/core/fpdfapi/parser/cpdf_parser_unittest.cpp index 06328f0..efde90e 100644 --- a/core/fpdfapi/parser/cpdf_parser_unittest.cpp +++ b/core/fpdfapi/parser/cpdf_parser_unittest.cpp
@@ -1,23 +1,28 @@ -// Copyright 2015 PDFium Authors. All rights reserved. +// Copyright 2015 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include "core/fpdfapi/parser/cpdf_parser.h" + #include <limits> #include <memory> #include <string> +#include <utility> #include <vector> +#include "core/fpdfapi/parser/cpdf_dictionary.h" #include "core/fpdfapi/parser/cpdf_linearized_header.h" #include "core/fpdfapi/parser/cpdf_object.h" -#include "core/fpdfapi/parser/cpdf_parser.h" #include "core/fpdfapi/parser/cpdf_syntax_parser.h" -#include "core/fxcrt/cfx_readonlymemorystream.h" +#include "core/fxcrt/cfx_read_only_span_stream.h" #include "core/fxcrt/fx_extension.h" #include "core/fxcrt/fx_stream.h" #include "core/fxcrt/retain_ptr.h" +#include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" #include "testing/utils/path_service.h" -#include "third_party/base/ptr_util.h" + +using testing::Return; namespace { @@ -27,13 +32,23 @@ return info ? *info : CPDF_CrossRefTable::ObjectInfo(); } +class TestObjectsHolder final : public CPDF_Parser::ParsedObjectsHolder { + public: + TestObjectsHolder() = default; + ~TestObjectsHolder() override = default; + + // CPDF_Parser::ParsedObjectsHolder: + bool TryInit() override { return true; } + MOCK_METHOD1(ParseIndirectObject, RetainPtr<CPDF_Object>(uint32_t objnum)); +}; + } // namespace // A wrapper class to help test member functions of CPDF_Parser. class CPDF_TestParser final : public CPDF_Parser { public: - CPDF_TestParser() {} - ~CPDF_TestParser() {} + CPDF_TestParser() : CPDF_Parser(&object_holder_) {} + ~CPDF_TestParser() = default; // Setup reading from a file and initial states. bool InitTestFromFile(const char* path) { @@ -43,15 +58,16 @@ return false; // For the test file, the header is set at the beginning. - m_pSyntax = pdfium::MakeUnique<CPDF_SyntaxParser>(pFileAccess); + SetSyntaxParserForTesting( + std::make_unique<CPDF_SyntaxParser>(std::move(pFileAccess))); return true; } // Setup reading from a buffer and initial states. bool InitTestFromBufferWithOffset(pdfium::span<const uint8_t> buffer, FX_FILESIZE header_offset) { - m_pSyntax = CPDF_SyntaxParser::CreateForTesting( - pdfium::MakeRetain<CFX_ReadOnlyMemoryStream>(buffer), header_offset); + SetSyntaxParserForTesting(CPDF_SyntaxParser::CreateForTesting( + pdfium::MakeRetain<CFX_ReadOnlySpanStream>(buffer), header_offset)); return true; } @@ -59,17 +75,20 @@ return InitTestFromBufferWithOffset(buffer, 0 /*header_offset*/); } + // Expose protected CPDF_Parser methods for testing. + using CPDF_Parser::LoadCrossRefV4; + using CPDF_Parser::ParseLinearizedHeader; + using CPDF_Parser::ParseStartXRef; + using CPDF_Parser::RebuildCrossRef; + using CPDF_Parser::StartParseInternal; + + TestObjectsHolder& object_holder() { return object_holder_; } + private: - // Add test cases here as private friend so that protected members in - // CPDF_Parser can be accessed by test cases. - // Need to access RebuildCrossRef. - FRIEND_TEST(cpdf_parser, RebuildCrossRefCorrectly); - FRIEND_TEST(cpdf_parser, RebuildCrossRefFailed); - // Need to access LoadCrossRefV4. - FRIEND_TEST(cpdf_parser, LoadCrossRefV4); + TestObjectsHolder object_holder_; }; -TEST(cpdf_parser, RebuildCrossRefCorrectly) { +TEST(ParserTest, RebuildCrossRefCorrectly) { CPDF_TestParser parser; std::string test_file; ASSERT_TRUE(PathService::GetTestFilePath("parser_rebuildxref_correct.pdf", @@ -79,13 +98,17 @@ ASSERT_TRUE(parser.RebuildCrossRef()); const FX_FILESIZE offsets[] = {0, 15, 61, 154, 296, 374, 450}; const uint16_t versions[] = {0, 0, 2, 4, 6, 8, 0}; - for (size_t i = 0; i < FX_ArraySize(offsets); ++i) + for (size_t i = 0; i < std::size(offsets); ++i) EXPECT_EQ(offsets[i], GetObjInfo(parser, i).pos); - for (size_t i = 0; i < FX_ArraySize(versions); ++i) + for (size_t i = 0; i < std::size(versions); ++i) EXPECT_EQ(versions[i], GetObjInfo(parser, i).gennum); + + const CPDF_CrossRefTable* cross_ref_table = parser.GetCrossRefTable(); + ASSERT_TRUE(cross_ref_table); + EXPECT_EQ(0u, cross_ref_table->trailer_object_number()); } -TEST(cpdf_parser, RebuildCrossRefFailed) { +TEST(ParserTest, RebuildCrossRefFailed) { CPDF_TestParser parser; std::string test_file; ASSERT_TRUE(PathService::GetTestFilePath( @@ -95,7 +118,7 @@ ASSERT_FALSE(parser.RebuildCrossRef()); } -TEST(cpdf_parser, LoadCrossRefV4) { +TEST(ParserTest, LoadCrossRefV4) { { static const unsigned char kXrefTable[] = "xref \n" @@ -119,9 +142,9 @@ CPDF_TestParser::ObjectType::kFree, CPDF_TestParser::ObjectType::kNotCompressed, CPDF_TestParser::ObjectType::kNotCompressed}; - static_assert(FX_ArraySize(kOffsets) == FX_ArraySize(kTypes), + static_assert(std::size(kOffsets) == std::size(kTypes), "kOffsets / kTypes size mismatch"); - for (size_t i = 0; i < FX_ArraySize(kOffsets); ++i) { + for (size_t i = 0; i < std::size(kOffsets); ++i) { EXPECT_EQ(kOffsets[i], GetObjInfo(parser, i).pos); EXPECT_EQ(kTypes[i], GetObjInfo(parser, i).type); } @@ -159,9 +182,9 @@ CPDF_TestParser::ObjectType::kFree, CPDF_TestParser::ObjectType::kFree, CPDF_TestParser::ObjectType::kNotCompressed}; - static_assert(FX_ArraySize(kOffsets) == FX_ArraySize(kTypes), + static_assert(std::size(kOffsets) == std::size(kTypes), "kOffsets / kTypes size mismatch"); - for (size_t i = 0; i < FX_ArraySize(kOffsets); ++i) { + for (size_t i = 0; i < std::size(kOffsets); ++i) { EXPECT_EQ(kOffsets[i], GetObjInfo(parser, i).pos); EXPECT_EQ(kTypes[i], GetObjInfo(parser, i).type); } @@ -199,9 +222,9 @@ CPDF_TestParser::ObjectType::kFree, CPDF_TestParser::ObjectType::kFree, CPDF_TestParser::ObjectType::kNotCompressed}; - static_assert(FX_ArraySize(kOffsets) == FX_ArraySize(kTypes), + static_assert(std::size(kOffsets) == std::size(kTypes), "kOffsets / kTypes size mismatch"); - for (size_t i = 0; i < FX_ArraySize(kOffsets); ++i) { + for (size_t i = 0; i < std::size(kOffsets); ++i) { EXPECT_EQ(kOffsets[i], GetObjInfo(parser, i).pos); EXPECT_EQ(kTypes[i], GetObjInfo(parser, i).type); } @@ -231,9 +254,9 @@ CPDF_TestParser::ObjectType::kFree, CPDF_TestParser::ObjectType::kNotCompressed, CPDF_TestParser::ObjectType::kNotCompressed}; - static_assert(FX_ArraySize(kOffsets) == FX_ArraySize(kTypes), + static_assert(std::size(kOffsets) == std::size(kTypes), "kOffsets / kTypes size mismatch"); - for (size_t i = 0; i < FX_ArraySize(kOffsets); ++i) { + for (size_t i = 0; i < std::size(kOffsets); ++i) { EXPECT_EQ(kOffsets[i], GetObjInfo(parser, i).pos); EXPECT_EQ(kTypes[i], GetObjInfo(parser, i).type); } @@ -264,7 +287,7 @@ } } -TEST(cpdf_parser, ParseStartXRef) { +TEST(ParserTest, ParseStartXRef) { CPDF_TestParser parser; std::string test_file; ASSERT_TRUE( @@ -278,7 +301,7 @@ EXPECT_EQ(75u, cross_ref_v5_obj->GetObjNum()); } -TEST(cpdf_parser, ParseStartXRefWithHeaderOffset) { +TEST(ParserTest, ParseStartXRefWithHeaderOffset) { static constexpr FX_FILESIZE kTestHeaderOffset = 765; std::string test_file; ASSERT_TRUE( @@ -288,8 +311,8 @@ ASSERT_TRUE(pFileAccess); std::vector<unsigned char> data(pFileAccess->GetSize() + kTestHeaderOffset); - ASSERT_TRUE(pFileAccess->ReadBlockAtOffset(&data.front() + kTestHeaderOffset, - 0, pFileAccess->GetSize())); + ASSERT_TRUE(pFileAccess->ReadBlockAtOffset( + pdfium::make_span(data).subspan(kTestHeaderOffset), 0)); CPDF_TestParser parser; parser.InitTestFromBufferWithOffset(data, kTestHeaderOffset); @@ -300,7 +323,7 @@ EXPECT_EQ(75u, cross_ref_v5_obj->GetObjNum()); } -TEST(cpdf_parser, ParseLinearizedWithHeaderOffset) { +TEST(ParserTest, ParseLinearizedWithHeaderOffset) { static constexpr FX_FILESIZE kTestHeaderOffset = 765; std::string test_file; ASSERT_TRUE(PathService::GetTestFilePath("linearized.pdf", &test_file)); @@ -309,15 +332,19 @@ ASSERT_TRUE(pFileAccess); std::vector<unsigned char> data(pFileAccess->GetSize() + kTestHeaderOffset); - ASSERT_TRUE(pFileAccess->ReadBlockAtOffset(&data.front() + kTestHeaderOffset, - 0, pFileAccess->GetSize())); + ASSERT_TRUE(pFileAccess->ReadBlockAtOffset( + pdfium::make_span(data).subspan(kTestHeaderOffset), 0)); + CPDF_TestParser parser; parser.InitTestFromBufferWithOffset(data, kTestHeaderOffset); - EXPECT_TRUE(parser.ParseLinearizedHeader()); + + const CPDF_CrossRefTable* cross_ref_table = parser.GetCrossRefTable(); + ASSERT_TRUE(cross_ref_table); + EXPECT_EQ(0u, cross_ref_table->trailer_object_number()); } -TEST(cpdf_parser, BadStartXrefShouldNotBuildCrossRefTable) { +TEST(ParserTest, BadStartXrefShouldNotBuildCrossRefTable) { const unsigned char kData[] = "%PDF1-7 0 obj <</Size 2 /W [0 0 0]\n>>\n" "stream\n" @@ -333,3 +360,103 @@ ASSERT_TRUE(parser.GetCrossRefTable()); EXPECT_EQ(0u, parser.GetCrossRefTable()->objects_info().size()); } + +TEST(ParserTest, XrefObjectIndicesTooBig) { + CPDF_TestParser parser; + + // Satisfy CPDF_Parser's checks, so the test data below can concentrate on the + // /XRef stream and avoid also providing other valid dictionaries. + auto dummy_root = pdfium::MakeRetain<CPDF_Dictionary>(); + EXPECT_CALL(parser.object_holder(), ParseIndirectObject) + .WillRepeatedly(Return(dummy_root)); + + // Since /Index starts at 4194303, the object number will go past + // `kMaxObjectNumber`. + static_assert(CPDF_Parser::kMaxObjectNumber == 4194304, + "Unexpected kMaxObjectNumber"); + const unsigned char kData[] = + "%PDF1-7\n%\xa0\xf2\xa4\xf4\n" + "7 0 obj <<\n" + " /Filter /ASCIIHexDecode\n" + " /Index [4194303 3]\n" + " /Root 1 0 R\n" + " /Size 4194306\n" + " /W [1 1 1]\n" + ">>\n" + "stream\n" + "01 00 00\n" + "01 0F 00\n" + "01 12 00\n" + "endstream\n" + "endobj\n" + "startxref\n" + "14\n" + "%%EOF\n"; + ASSERT_TRUE(parser.InitTestFromBuffer(kData)); + EXPECT_EQ(CPDF_Parser::SUCCESS, parser.StartParseInternal()); + ASSERT_TRUE(parser.GetCrossRefTable()); + const auto& objects_info = parser.GetCrossRefTable()->objects_info(); + EXPECT_EQ(2u, objects_info.size()); + + // This should be the only object from table. Subsequent objects have object + // numbers that are too big. + auto first_object_it = objects_info.find(4194303); + ASSERT_NE(first_object_it, objects_info.end()); + EXPECT_EQ(CPDF_Parser::ObjectType::kNormal, first_object_it->second.type); + EXPECT_EQ(0, first_object_it->second.pos); + + // TODO(thestig): Should the xref table contain object 4194305? + // Consider reworking CPDF_Parser's object representation to avoid having to + // store this placeholder object. + auto placeholder_object_it = objects_info.find(4194305); + ASSERT_NE(placeholder_object_it, objects_info.end()); + EXPECT_EQ(CPDF_Parser::ObjectType::kFree, placeholder_object_it->second.type); +} + +TEST(ParserTest, XrefHasInvalidArchiveObjectNumber) { + CPDF_TestParser parser; + + // Satisfy CPDF_Parser's checks, so the test data below can concentrate on the + // /XRef stream and avoid also providing other valid dictionaries. + auto dummy_root = pdfium::MakeRetain<CPDF_Dictionary>(); + EXPECT_CALL(parser.object_holder(), ParseIndirectObject) + .WillRepeatedly(Return(dummy_root)); + + // 0xFF in the first object in the xref object stream is invalid. + const unsigned char kData[] = + "%PDF1-7\n%\xa0\xf2\xa4\xf4\n" + "7 0 obj <<\n" + " /Filter /ASCIIHexDecode\n" + " /Root 1 0 R\n" + " /Size 3\n" + " /W [1 1 1]\n" + ">>\n" + "stream\n" + "02 FF 00\n" + "01 0F 00\n" + "01 12 00\n" + "endstream\n" + "endobj\n" + "startxref\n" + "14\n" + "%%EOF\n"; + ASSERT_TRUE(parser.InitTestFromBuffer(kData)); + EXPECT_EQ(CPDF_Parser::SUCCESS, parser.StartParseInternal()); + + const CPDF_CrossRefTable* cross_ref_table = parser.GetCrossRefTable(); + ASSERT_TRUE(cross_ref_table); + EXPECT_EQ(7u, cross_ref_table->trailer_object_number()); + const auto& objects_info = cross_ref_table->objects_info(); + EXPECT_EQ(2u, objects_info.size()); + + // Skip over the first object, and continue parsing the remaining objects. + auto second_object_it = objects_info.find(1); + ASSERT_NE(second_object_it, objects_info.end()); + EXPECT_EQ(CPDF_Parser::ObjectType::kNormal, second_object_it->second.type); + EXPECT_EQ(15, second_object_it->second.pos); + + auto third_object_it = objects_info.find(2); + ASSERT_NE(third_object_it, objects_info.end()); + EXPECT_EQ(CPDF_Parser::ObjectType::kNormal, third_object_it->second.type); + EXPECT_EQ(18, third_object_it->second.pos); +}
diff --git a/core/fpdfapi/parser/cpdf_read_validator.cpp b/core/fpdfapi/parser/cpdf_read_validator.cpp index 80e6517..b6fd872 100644 --- a/core/fpdfapi/parser/cpdf_read_validator.cpp +++ b/core/fpdfapi/parser/cpdf_read_validator.cpp
@@ -1,14 +1,15 @@ -// Copyright 2017 PDFium Authors. All rights reserved. +// Copyright 2017 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "core/fpdfapi/parser/cpdf_read_validator.h" #include <algorithm> +#include <utility> #include "core/fpdfapi/parser/cpdf_stream.h" #include "core/fxcrt/fx_safe_types.h" -#include "third_party/base/logging.h" +#include "third_party/base/notreached.h" namespace { @@ -26,55 +27,55 @@ } // namespace -CPDF_ReadValidator::Session::Session( - const RetainPtr<CPDF_ReadValidator>& validator) - : validator_(validator.BackPointer()) { - ASSERT(validator_); - saved_read_error_ = validator_->read_error_; - saved_has_unavailable_data_ = validator_->has_unavailable_data_; +CPDF_ReadValidator::ScopedSession::ScopedSession( + RetainPtr<CPDF_ReadValidator> validator) + : validator_(std::move(validator)), + saved_read_error_(validator_->read_error_), + saved_has_unavailable_data_(validator_->has_unavailable_data_) { validator_->ResetErrors(); } -CPDF_ReadValidator::Session::~Session() { +CPDF_ReadValidator::ScopedSession::~ScopedSession() { validator_->read_error_ |= saved_read_error_; validator_->has_unavailable_data_ |= saved_has_unavailable_data_; } CPDF_ReadValidator::CPDF_ReadValidator( - const RetainPtr<IFX_SeekableReadStream>& file_read, + RetainPtr<IFX_SeekableReadStream> file_read, CPDF_DataAvail::FileAvail* file_avail) - : file_read_(file_read), + : file_read_(std::move(file_read)), file_avail_(file_avail), - read_error_(false), - has_unavailable_data_(false), - whole_file_already_available_(false), - file_size_(file_read->GetSize()) {} + file_size_(file_read_->GetSize()) {} -CPDF_ReadValidator::~CPDF_ReadValidator() {} +CPDF_ReadValidator::~CPDF_ReadValidator() = default; void CPDF_ReadValidator::ResetErrors() { read_error_ = false; has_unavailable_data_ = false; } -bool CPDF_ReadValidator::ReadBlockAtOffset(void* buffer, - FX_FILESIZE offset, - size_t size) { - FX_SAFE_FILESIZE end_offset = offset; - end_offset += size; - if (!end_offset.IsValid() || end_offset.ValueOrDie() > file_size_) - return false; - - if (!IsDataRangeAvailable(offset, size)) { - ScheduleDownload(offset, size); +bool CPDF_ReadValidator::ReadBlockAtOffset(pdfium::span<uint8_t> buffer, + FX_FILESIZE offset) { + if (offset < 0) { + NOTREACHED(); return false; } - if (file_read_->ReadBlockAtOffset(buffer, offset, size)) + FX_SAFE_FILESIZE end_offset = offset; + end_offset += buffer.size(); + if (!end_offset.IsValid() || end_offset.ValueOrDie() > file_size_) + return false; + + if (!IsDataRangeAvailable(offset, buffer.size())) { + ScheduleDownload(offset, buffer.size()); + return false; + } + + if (file_read_->ReadBlockAtOffset(buffer, offset)) return true; read_error_ = true; - ScheduleDownload(offset, size); + ScheduleDownload(offset, buffer.size()); return false; } @@ -116,8 +117,7 @@ const FX_SAFE_SIZE_T safe_size = file_size_; whole_file_already_available_ = whole_file_already_available_ || - (safe_size.IsValid() ? IsDataRangeAvailable(0, safe_size.ValueOrDie()) - : false); + (safe_size.IsValid() && IsDataRangeAvailable(0, safe_size.ValueOrDie())); return whole_file_already_available_; }
diff --git a/core/fpdfapi/parser/cpdf_read_validator.h b/core/fpdfapi/parser/cpdf_read_validator.h index 6adde02..c866541 100644 --- a/core/fpdfapi/parser/cpdf_read_validator.h +++ b/core/fpdfapi/parser/cpdf_read_validator.h
@@ -1,4 +1,4 @@ -// Copyright 2017 PDFium Authors. All rights reserved. +// Copyright 2017 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -6,23 +6,29 @@ #define CORE_FPDFAPI_PARSER_CPDF_READ_VALIDATOR_H_ #include "core/fpdfapi/parser/cpdf_data_avail.h" +#include "core/fxcrt/fx_memory.h" #include "core/fxcrt/fx_stream.h" +#include "core/fxcrt/retain_ptr.h" +#include "core/fxcrt/unowned_ptr.h" class CPDF_ReadValidator : public IFX_SeekableReadStream { public: - class Session { + class ScopedSession { public: - explicit Session(const RetainPtr<CPDF_ReadValidator>& validator); - ~Session(); + FX_STACK_ALLOCATED(); + + explicit ScopedSession(RetainPtr<CPDF_ReadValidator> validator); + ScopedSession(const ScopedSession& that) = delete; + ScopedSession& operator=(const ScopedSession& that) = delete; + ~ScopedSession(); private: - UnownedPtr<CPDF_ReadValidator> validator_; - bool saved_read_error_; - bool saved_has_unavailable_data_; + RetainPtr<CPDF_ReadValidator> const validator_; + const bool saved_read_error_; + const bool saved_has_unavailable_data_; }; - template <typename T, typename... Args> - friend RetainPtr<T> pdfium::MakeRetain(Args&&... args); + CONSTRUCT_VIA_MAKE_RETAIN; void SetDownloadHints(CPDF_DataAvail::DownloadHints* hints) { hints_ = hints; @@ -34,20 +40,17 @@ } void ResetErrors(); - bool IsWholeFileAvailable(); - bool CheckDataRangeAndRequestIfUnavailable(FX_FILESIZE offset, size_t size); bool CheckWholeFileAndRequestIfUnavailable(); // IFX_SeekableReadStream overrides: - bool ReadBlockAtOffset(void* buffer, - FX_FILESIZE offset, - size_t size) override; + bool ReadBlockAtOffset(pdfium::span<uint8_t> buffer, + FX_FILESIZE offset) override; FX_FILESIZE GetSize() override; protected: - CPDF_ReadValidator(const RetainPtr<IFX_SeekableReadStream>& file_read, + CPDF_ReadValidator(RetainPtr<IFX_SeekableReadStream> file_read, CPDF_DataAvail::FileAvail* file_avail); ~CPDF_ReadValidator() override; @@ -55,14 +58,12 @@ void ScheduleDownload(FX_FILESIZE offset, size_t size); bool IsDataRangeAvailable(FX_FILESIZE offset, size_t size) const; - RetainPtr<IFX_SeekableReadStream> file_read_; - UnownedPtr<CPDF_DataAvail::FileAvail> file_avail_; - + RetainPtr<IFX_SeekableReadStream> const file_read_; + UnownedPtr<CPDF_DataAvail::FileAvail> const file_avail_; UnownedPtr<CPDF_DataAvail::DownloadHints> hints_; - - bool read_error_; - bool has_unavailable_data_; - bool whole_file_already_available_; + bool read_error_ = false; + bool has_unavailable_data_ = false; + bool whole_file_already_available_ = false; const FX_FILESIZE file_size_; };
diff --git a/core/fpdfapi/parser/cpdf_read_validator_unittest.cpp b/core/fpdfapi/parser/cpdf_read_validator_unittest.cpp index 38b4bf9..bb3006a 100644 --- a/core/fpdfapi/parser/cpdf_read_validator_unittest.cpp +++ b/core/fpdfapi/parser/cpdf_read_validator_unittest.cpp
@@ -1,14 +1,17 @@ -// Copyright 2017 PDFium Authors. All rights reserved. +// Copyright 2017 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "core/fpdfapi/parser/cpdf_read_validator.h" +#include <stdint.h> + #include <limits> #include <utility> -#include <vector> -#include "core/fxcrt/cfx_readonlymemorystream.h" +#include "core/fxcrt/cfx_read_only_span_stream.h" +#include "core/fxcrt/cfx_read_only_vector_stream.h" +#include "core/fxcrt/data_vector.h" #include "testing/gtest/include/gtest/gtest.h" #include "testing/invalid_seekable_read_stream.h" @@ -23,7 +26,7 @@ class MockFileAvail final : public CPDF_DataAvail::FileAvail { public: MockFileAvail() : available_range_(0, 0) {} - ~MockFileAvail() override {} + ~MockFileAvail() override = default; bool IsDataAvail(FX_FILESIZE offset, size_t size) override { return available_range_.first <= offset && @@ -45,7 +48,7 @@ class MockDownloadHints final : public CPDF_DataAvail::DownloadHints { public: MockDownloadHints() : last_requested_range_(0, 0) {} - ~MockDownloadHints() override {} + ~MockDownloadHints() override = default; void AddSegment(FX_FILESIZE offset, size_t size) override { last_requested_range_.first = offset; @@ -64,42 +67,39 @@ } // namespace -TEST(CPDF_ReadValidatorTest, UnavailableData) { - std::vector<uint8_t> test_data(kTestDataSize); - auto file = pdfium::MakeRetain<CFX_ReadOnlyMemoryStream>(test_data); +TEST(ReadValidatorTest, UnavailableData) { + DataVector<uint8_t> test_data(kTestDataSize); + auto file = + pdfium::MakeRetain<CFX_ReadOnlyVectorStream>(std::move(test_data)); MockFileAvail file_avail; - auto validator = pdfium::MakeRetain<CPDF_ReadValidator>(file, &file_avail); + auto validator = + pdfium::MakeRetain<CPDF_ReadValidator>(std::move(file), &file_avail); - std::vector<uint8_t> read_buffer(100); - EXPECT_FALSE(validator->ReadBlockAtOffset(read_buffer.data(), 5000, - read_buffer.size())); - + DataVector<uint8_t> read_buffer(100); + EXPECT_FALSE(validator->ReadBlockAtOffset(read_buffer, 5000)); EXPECT_FALSE(validator->read_error()); EXPECT_TRUE(validator->has_unavailable_data()); validator->ResetErrors(); - file_avail.SetAvailableRange(5000, 5000 + read_buffer.size()); - - EXPECT_TRUE(validator->ReadBlockAtOffset(read_buffer.data(), 5000, - read_buffer.size())); + EXPECT_TRUE(validator->ReadBlockAtOffset(read_buffer, 5000)); EXPECT_FALSE(validator->read_error()); EXPECT_FALSE(validator->has_unavailable_data()); } -TEST(CPDF_ReadValidatorTest, UnavailableDataWithHints) { - std::vector<uint8_t> test_data(kTestDataSize); - auto file = pdfium::MakeRetain<CFX_ReadOnlyMemoryStream>(test_data); +TEST(ReadValidatorTest, UnavailableDataWithHints) { + DataVector<uint8_t> test_data(kTestDataSize); + auto file = + pdfium::MakeRetain<CFX_ReadOnlyVectorStream>(std::move(test_data)); MockFileAvail file_avail; - auto validator = pdfium::MakeRetain<CPDF_ReadValidator>(file, &file_avail); + auto validator = + pdfium::MakeRetain<CPDF_ReadValidator>(std::move(file), &file_avail); MockDownloadHints hints; validator->SetDownloadHints(&hints); - std::vector<uint8_t> read_buffer(100); - - EXPECT_FALSE(validator->ReadBlockAtOffset(read_buffer.data(), 5000, - read_buffer.size())); + DataVector<uint8_t> read_buffer(100); + EXPECT_FALSE(validator->ReadBlockAtOffset(read_buffer, 5000)); EXPECT_FALSE(validator->read_error()); EXPECT_TRUE(validator->has_unavailable_data()); @@ -110,8 +110,7 @@ hints.Reset(); validator->ResetErrors(); - EXPECT_TRUE(validator->ReadBlockAtOffset(read_buffer.data(), 5000, - read_buffer.size())); + EXPECT_TRUE(validator->ReadBlockAtOffset(read_buffer, 5000)); // No new request on already available data. EXPECT_EQ(MakeRange(0, 0), hints.GetLastRequstedRange()); EXPECT_FALSE(validator->read_error()); @@ -120,8 +119,7 @@ validator->ResetErrors(); // Try read unavailable data at file end. EXPECT_FALSE(validator->ReadBlockAtOffset( - read_buffer.data(), validator->GetSize() - read_buffer.size(), - read_buffer.size())); + read_buffer, validator->GetSize() - read_buffer.size())); // Should not enlarge request at file end. EXPECT_EQ(validator->GetSize(), hints.GetLastRequstedRange().second); EXPECT_FALSE(validator->read_error()); @@ -130,63 +128,66 @@ validator->SetDownloadHints(nullptr); } -TEST(CPDF_ReadValidatorTest, ReadError) { +TEST(ReadValidatorTest, ReadError) { auto file = pdfium::MakeRetain<InvalidSeekableReadStream>(kTestDataSize); - auto validator = pdfium::MakeRetain<CPDF_ReadValidator>(file, nullptr); + auto validator = + pdfium::MakeRetain<CPDF_ReadValidator>(std::move(file), nullptr); static const uint32_t kBufferSize = 3 * 1000; - std::vector<uint8_t> buffer(kBufferSize); + DataVector<uint8_t> buffer(kBufferSize); - EXPECT_FALSE(validator->ReadBlockAtOffset(buffer.data(), 5000, 100)); + EXPECT_FALSE( + validator->ReadBlockAtOffset(pdfium::make_span(buffer).first(100), 5000)); EXPECT_TRUE(validator->read_error()); EXPECT_TRUE(validator->has_unavailable_data()); } -TEST(CPDF_ReadValidatorTest, IntOverflow) { - std::vector<uint8_t> test_data(kTestDataSize); - auto file = pdfium::MakeRetain<CFX_ReadOnlyMemoryStream>(test_data); +TEST(ReadValidatorTest, IntOverflow) { + DataVector<uint8_t> test_data(kTestDataSize); + auto file = + pdfium::MakeRetain<CFX_ReadOnlyVectorStream>(std::move(test_data)); MockFileAvail file_avail; - auto validator = pdfium::MakeRetain<CPDF_ReadValidator>(file, &file_avail); + auto validator = + pdfium::MakeRetain<CPDF_ReadValidator>(std::move(file), &file_avail); - std::vector<uint8_t> read_buffer(100); + DataVector<uint8_t> read_buffer(100); // If we have int overflow, this is equal reading after file end. This is not // read_error, and in this case we have not unavailable data. It is just error // of input params. EXPECT_FALSE(validator->ReadBlockAtOffset( - read_buffer.data(), std::numeric_limits<FX_FILESIZE>::max() - 1, - read_buffer.size())); + read_buffer, std::numeric_limits<FX_FILESIZE>::max() - 1)); EXPECT_FALSE(validator->read_error()); EXPECT_FALSE(validator->has_unavailable_data()); } -TEST(CPDF_ReadValidatorTest, Session) { - std::vector<uint8_t> test_data(kTestDataSize); +TEST(ReadValidatorTest, Session) { + DataVector<uint8_t> test_data(kTestDataSize); auto file = pdfium::MakeRetain<InvalidSeekableReadStream>(kTestDataSize); MockFileAvail file_avail; MockDownloadHints hints; - auto validator = pdfium::MakeRetain<CPDF_ReadValidator>(file, &file_avail); + auto validator = + pdfium::MakeRetain<CPDF_ReadValidator>(std::move(file), &file_avail); validator->SetDownloadHints(&hints); - const CPDF_ReadValidator::Session read_session(validator); + CPDF_ReadValidator::ScopedSession read_session(validator); ASSERT_FALSE(validator->has_read_problems()); // Data is unavailable - validator->ReadBlockAtOffset(test_data.data(), 0, 100); - + validator->ReadBlockAtOffset(pdfium::make_span(test_data).first(100), 0); EXPECT_TRUE(validator->has_read_problems()); EXPECT_TRUE(validator->has_unavailable_data()); EXPECT_FALSE(validator->read_error()); { - const CPDF_ReadValidator::Session read_subsession(validator); + CPDF_ReadValidator::ScopedSession read_subsession(validator); // The read problems should be hidden. EXPECT_FALSE(validator->has_read_problems()); file_avail.SetAvailableRange(0, 100); // Read fail. - validator->ReadBlockAtOffset(test_data.data(), 0, 100); + validator->ReadBlockAtOffset(pdfium::make_span(test_data).first(100), 0); EXPECT_TRUE(validator->has_read_problems()); EXPECT_TRUE(validator->has_unavailable_data()); EXPECT_TRUE(validator->read_error()); @@ -198,33 +199,33 @@ EXPECT_TRUE(validator->read_error()); } -TEST(CPDF_ReadValidatorTest, SessionReset) { - std::vector<uint8_t> test_data(kTestDataSize); +TEST(ReadValidatorTest, SessionReset) { + DataVector<uint8_t> test_data(kTestDataSize); auto file = pdfium::MakeRetain<InvalidSeekableReadStream>(kTestDataSize); MockFileAvail file_avail; MockDownloadHints hints; - auto validator = pdfium::MakeRetain<CPDF_ReadValidator>(file, &file_avail); + auto validator = + pdfium::MakeRetain<CPDF_ReadValidator>(std::move(file), &file_avail); validator->SetDownloadHints(&hints); - const CPDF_ReadValidator::Session read_session(validator); + CPDF_ReadValidator::ScopedSession read_session(validator); ASSERT_FALSE(validator->has_read_problems()); // Data is unavailable - validator->ReadBlockAtOffset(test_data.data(), 0, 100); - + validator->ReadBlockAtOffset(pdfium::make_span(test_data).first(100), 0); EXPECT_TRUE(validator->has_read_problems()); EXPECT_TRUE(validator->has_unavailable_data()); EXPECT_FALSE(validator->read_error()); { - const CPDF_ReadValidator::Session read_subsession(validator); + CPDF_ReadValidator::ScopedSession read_subsession(validator); // The read problems should be hidden. EXPECT_FALSE(validator->has_read_problems()); file_avail.SetAvailableRange(0, 100); // Read fail. - validator->ReadBlockAtOffset(test_data.data(), 0, 100); + validator->ReadBlockAtOffset(pdfium::make_span(test_data).first(100), 0); EXPECT_TRUE(validator->has_read_problems()); EXPECT_TRUE(validator->has_unavailable_data()); EXPECT_TRUE(validator->read_error()); @@ -240,11 +241,13 @@ EXPECT_FALSE(validator->read_error()); } -TEST(CPDF_ReadValidatorTest, CheckDataRangeAndRequestIfUnavailable) { - std::vector<uint8_t> test_data(kTestDataSize); - auto file = pdfium::MakeRetain<CFX_ReadOnlyMemoryStream>(test_data); +TEST(ReadValidatorTest, CheckDataRangeAndRequestIfUnavailable) { + DataVector<uint8_t> test_data(kTestDataSize); + auto file = + pdfium::MakeRetain<CFX_ReadOnlyVectorStream>(std::move(test_data)); MockFileAvail file_avail; - auto validator = pdfium::MakeRetain<CPDF_ReadValidator>(file, &file_avail); + auto validator = + pdfium::MakeRetain<CPDF_ReadValidator>(std::move(file), &file_avail); MockDownloadHints hints; validator->SetDownloadHints(&hints); @@ -266,9 +269,8 @@ EXPECT_FALSE(validator->read_error()); EXPECT_FALSE(validator->has_unavailable_data()); - std::vector<uint8_t> read_buffer(100); - EXPECT_TRUE(validator->ReadBlockAtOffset(read_buffer.data(), 5000, - read_buffer.size())); + DataVector<uint8_t> read_buffer(100); + EXPECT_TRUE(validator->ReadBlockAtOffset(read_buffer, 5000)); // No new request on already available data. EXPECT_EQ(MakeRange(0, 0), hints.GetLastRequstedRange()); EXPECT_FALSE(validator->read_error());
diff --git a/core/fpdfapi/parser/cpdf_reference.cpp b/core/fpdfapi/parser/cpdf_reference.cpp index d50db34..8baa6b6 100644 --- a/core/fpdfapi/parser/cpdf_reference.cpp +++ b/core/fpdfapi/parser/cpdf_reference.cpp
@@ -1,4 +1,4 @@ -// Copyright 2016 PDFium Authors. All rights reserved. +// Copyright 2016 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -6,54 +6,42 @@ #include "core/fpdfapi/parser/cpdf_reference.h" +#include "core/fpdfapi/parser/cpdf_dictionary.h" #include "core/fpdfapi/parser/cpdf_indirect_object_holder.h" #include "core/fxcrt/fx_stream.h" -#include "third_party/base/ptr_util.h" -#include "third_party/base/stl_util.h" +#include "third_party/base/check_op.h" +#include "third_party/base/containers/contains.h" CPDF_Reference::CPDF_Reference(CPDF_IndirectObjectHolder* pDoc, uint32_t objnum) : m_pObjList(pDoc), m_RefObjNum(objnum) {} -CPDF_Reference::~CPDF_Reference() {} +CPDF_Reference::~CPDF_Reference() = default; CPDF_Object::Type CPDF_Reference::GetType() const { return kReference; } ByteString CPDF_Reference::GetString() const { - const CPDF_Object* obj = SafeGetDirect(); + const CPDF_Object* obj = FastGetDirect(); return obj ? obj->GetString() : ByteString(); } float CPDF_Reference::GetNumber() const { - const CPDF_Object* obj = SafeGetDirect(); + const CPDF_Object* obj = FastGetDirect(); return obj ? obj->GetNumber() : 0; } int CPDF_Reference::GetInteger() const { - const CPDF_Object* obj = SafeGetDirect(); + const CPDF_Object* obj = FastGetDirect(); return obj ? obj->GetInteger() : 0; } -CPDF_Dictionary* CPDF_Reference::GetDict() { - CPDF_Object* obj = SafeGetDirect(); - return obj ? obj->GetDict() : nullptr; +const CPDF_Dictionary* CPDF_Reference::GetDictInternal() const { + const CPDF_Object* obj = FastGetDirect(); + return obj ? obj->GetDictInternal() : nullptr; } -const CPDF_Dictionary* CPDF_Reference::GetDict() const { - const CPDF_Object* obj = SafeGetDirect(); - return obj ? obj->GetDict() : nullptr; -} - -bool CPDF_Reference::IsReference() const { - return true; -} - -CPDF_Reference* CPDF_Reference::AsReference() { - return this; -} - -const CPDF_Reference* CPDF_Reference::AsReference() const { +CPDF_Reference* CPDF_Reference::AsMutableReference() { return this; } @@ -65,22 +53,20 @@ bool bDirect, std::set<const CPDF_Object*>* pVisited) const { pVisited->insert(this); - if (bDirect) { - auto* pDirect = GetDirect(); - return pDirect && !pdfium::ContainsKey(*pVisited, pDirect) - ? pDirect->CloneNonCyclic(true, pVisited) - : nullptr; + if (!bDirect) { + return pdfium::MakeRetain<CPDF_Reference>(m_pObjList, m_RefObjNum); } - return pdfium::MakeRetain<CPDF_Reference>(m_pObjList.Get(), m_RefObjNum); + RetainPtr<const CPDF_Object> pDirect = GetDirect(); + return pDirect && !pdfium::Contains(*pVisited, pDirect.Get()) + ? pDirect->CloneNonCyclic(true, pVisited) + : nullptr; } -CPDF_Object* CPDF_Reference::SafeGetDirect() { - CPDF_Object* obj = GetDirect(); - return (obj && !obj->IsReference()) ? obj : nullptr; -} - -const CPDF_Object* CPDF_Reference::SafeGetDirect() const { - const CPDF_Object* obj = GetDirect(); +const CPDF_Object* CPDF_Reference::FastGetDirect() const { + if (!m_pObjList) + return nullptr; + const CPDF_Object* obj = + m_pObjList->GetOrParseIndirectObjectInternal(m_RefObjNum); return (obj && !obj->IsReference()) ? obj : nullptr; } @@ -89,13 +75,8 @@ m_RefObjNum = objnum; } -CPDF_Object* CPDF_Reference::GetDirect() { - return m_pObjList ? m_pObjList->GetOrParseIndirectObject(m_RefObjNum) - : nullptr; -} - -const CPDF_Object* CPDF_Reference::GetDirect() const { - return m_pObjList ? m_pObjList->GetOrParseIndirectObject(m_RefObjNum) +const CPDF_Object* CPDF_Reference::GetDirectInternal() const { + return m_pObjList ? m_pObjList->GetOrParseIndirectObjectInternal(m_RefObjNum) : nullptr; } @@ -105,9 +86,9 @@ archive->WriteString(" 0 R "); } -RetainPtr<CPDF_Object> CPDF_Reference::MakeReference( +RetainPtr<CPDF_Reference> CPDF_Reference::MakeReference( CPDF_IndirectObjectHolder* holder) const { - ASSERT(holder == m_pObjList); + DCHECK_EQ(holder, m_pObjList); // Do not allow reference to reference, just create other reference for same // object. return pdfium::MakeRetain<CPDF_Reference>(holder, GetRefObjNum());
diff --git a/core/fpdfapi/parser/cpdf_reference.h b/core/fpdfapi/parser/cpdf_reference.h index 1ec7282..241b398 100644 --- a/core/fpdfapi/parser/cpdf_reference.h +++ b/core/fpdfapi/parser/cpdf_reference.h
@@ -1,4 +1,4 @@ -// Copyright 2016 PDFium Authors. All rights reserved. +// Copyright 2016 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -7,61 +7,67 @@ #ifndef CORE_FPDFAPI_PARSER_CPDF_REFERENCE_H_ #define CORE_FPDFAPI_PARSER_CPDF_REFERENCE_H_ -#include <memory> #include <set> #include "core/fpdfapi/parser/cpdf_object.h" +#include "core/fxcrt/retain_ptr.h" #include "core/fxcrt/unowned_ptr.h" class CPDF_IndirectObjectHolder; class CPDF_Reference final : public CPDF_Object { public: - template <typename T, typename... Args> - friend RetainPtr<T> pdfium::MakeRetain(Args&&... args); + CONSTRUCT_VIA_MAKE_RETAIN; // CPDF_Object: Type GetType() const override; RetainPtr<CPDF_Object> Clone() const override; - CPDF_Object* GetDirect() override; - const CPDF_Object* GetDirect() const override; ByteString GetString() const override; float GetNumber() const override; int GetInteger() const override; - CPDF_Dictionary* GetDict() override; - const CPDF_Dictionary* GetDict() const override; - bool IsReference() const override; - CPDF_Reference* AsReference() override; - const CPDF_Reference* AsReference() const override; + CPDF_Reference* AsMutableReference() override; bool WriteTo(IFX_ArchiveStream* archive, const CPDF_Encryptor* encryptor) const override; - RetainPtr<CPDF_Object> MakeReference( + RetainPtr<CPDF_Reference> MakeReference( CPDF_IndirectObjectHolder* holder) const override; - CPDF_IndirectObjectHolder* GetObjList() const { return m_pObjList.Get(); } uint32_t GetRefObjNum() const { return m_RefObjNum; } + bool HasIndirectObjectHolder() const { return !!m_pObjList; } void SetRef(CPDF_IndirectObjectHolder* pDoc, uint32_t objnum); private: + friend class CPDF_Dictionary; + CPDF_Reference(CPDF_IndirectObjectHolder* pDoc, uint32_t objnum); ~CPDF_Reference() override; + const CPDF_Object* GetDirectInternal() const override; + const CPDF_Dictionary* GetDictInternal() const override; RetainPtr<CPDF_Object> CloneNonCyclic( bool bDirect, std::set<const CPDF_Object*>* pVisited) const override; - CPDF_Object* SafeGetDirect(); - const CPDF_Object* SafeGetDirect() const; + + const CPDF_Object* FastGetDirect() const; UnownedPtr<CPDF_IndirectObjectHolder> m_pObjList; uint32_t m_RefObjNum; }; inline CPDF_Reference* ToReference(CPDF_Object* obj) { - return obj ? obj->AsReference() : nullptr; + return obj ? obj->AsMutableReference() : nullptr; } inline const CPDF_Reference* ToReference(const CPDF_Object* obj) { return obj ? obj->AsReference() : nullptr; } +inline RetainPtr<CPDF_Reference> ToReference(RetainPtr<CPDF_Object> obj) { + return RetainPtr<CPDF_Reference>(ToReference(obj.Get())); +} + +inline RetainPtr<const CPDF_Reference> ToReference( + RetainPtr<const CPDF_Object> obj) { + return RetainPtr<const CPDF_Reference>(ToReference(obj.Get())); +} + #endif // CORE_FPDFAPI_PARSER_CPDF_REFERENCE_H_
diff --git a/core/fpdfapi/parser/cpdf_security_handler.cpp b/core/fpdfapi/parser/cpdf_security_handler.cpp index 126fc6b..ff17c59 100644 --- a/core/fpdfapi/parser/cpdf_security_handler.cpp +++ b/core/fpdfapi/parser/cpdf_security_handler.cpp
@@ -1,4 +1,4 @@ -// Copyright 2014 PDFium Authors. All rights reserved. +// Copyright 2014 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -6,11 +6,11 @@ #include "core/fpdfapi/parser/cpdf_security_handler.h" +#include <stdint.h> #include <time.h> #include <algorithm> #include <utility> -#include <vector> #include "core/fdrm/fx_crypt.h" #include "core/fpdfapi/parser/cpdf_array.h" @@ -18,8 +18,11 @@ #include "core/fpdfapi/parser/cpdf_dictionary.h" #include "core/fpdfapi/parser/cpdf_object.h" #include "core/fpdfapi/parser/cpdf_string.h" +#include "core/fxcrt/data_vector.h" #include "core/fxcrt/fx_random.h" -#include "third_party/base/ptr_util.h" +#include "third_party/base/check.h" +#include "third_party/base/check_op.h" +#include "third_party/base/notreached.h" namespace { @@ -47,7 +50,7 @@ GetPassCode(password, passcode); CRYPT_md5_context md5 = CRYPT_MD5Start(); CRYPT_MD5Update(&md5, passcode); - ByteString okey = pEncrypt->GetStringFor("O"); + ByteString okey = pEncrypt->GetByteStringFor("O"); CRYPT_MD5Update(&md5, okey.raw_span()); uint32_t perm = pEncrypt->GetIntegerFor("P"); CRYPT_MD5Update(&md5, pdfium::as_bytes(pdfium::make_span(&perm, 1))); @@ -70,20 +73,18 @@ memcpy(key, digest, copy_len); } -bool IsValidKeyLengthForCipher(int cipher, size_t keylen) { +bool IsValidKeyLengthForCipher(CPDF_CryptoHandler::Cipher cipher, + size_t keylen) { switch (cipher) { - case FXCIPHER_AES: + case CPDF_CryptoHandler::Cipher::kAES: return keylen == 16 || keylen == 24 || keylen == 32; - case FXCIPHER_AES2: + case CPDF_CryptoHandler::Cipher::kAES2: return keylen == 32; - case FXCIPHER_RC4: + case CPDF_CryptoHandler::Cipher::kRC4: return keylen >= 5 && keylen <= 16; - case FXCIPHER_NONE: + case CPDF_CryptoHandler::Cipher::kNone: return true; - default: - NOTREACHED(); } - return false; } #define FX_GET_32WORD(n, b, i) \ @@ -118,13 +119,13 @@ uint8_t digest[32]; CRYPT_SHA256Finish(&sha, digest); - std::vector<uint8_t> buf; + DataVector<uint8_t> buf; uint8_t* input = digest; uint8_t* key = input; uint8_t* iv = input + 16; uint8_t* E = nullptr; int iBufLen = 0; - std::vector<uint8_t> interDigest; + DataVector<uint8_t> interDigest; int i = 0; int iBlockSize = 32; CRYPT_aes_context aes = {}; @@ -136,7 +137,7 @@ iBufLen = iRoundSize * 64; buf.resize(iBufLen); E = buf.data(); - std::vector<uint8_t> content; + DataVector<uint8_t> content; for (int j = 0; j < 64; ++j) { content.insert(std::end(content), password.raw_str(), password.raw_str() + password.GetLength()); @@ -145,7 +146,7 @@ content.insert(std::end(content), vector, vector + 48); } } - CRYPT_AESSetKey(&aes, key, 16, true); + CRYPT_AESSetKey(&aes, key, 16); CRYPT_AESSetIV(&aes, iv); CRYPT_AESEncrypt(&aes, E, content.data(), iBufLen); int iHash = 0; @@ -188,15 +189,15 @@ CPDF_SecurityHandler::~CPDF_SecurityHandler() = default; bool CPDF_SecurityHandler::OnInit(const CPDF_Dictionary* pEncryptDict, - const CPDF_Array* pIdArray, + RetainPtr<const CPDF_Array> pIdArray, const ByteString& password) { if (pIdArray) - m_FileId = pIdArray->GetStringAt(0); + m_FileId = pIdArray->GetByteStringAt(0); else m_FileId.clear(); if (!LoadDict(pEncryptDict)) return false; - if (m_Cipher == FXCIPHER_NONE) + if (m_Cipher == CPDF_CryptoHandler::Cipher::kNone) return true; if (!CheckSecurity(password)) return false; @@ -215,7 +216,8 @@ uint32_t CPDF_SecurityHandler::GetPermissions() const { uint32_t dwPermission = m_bOwnerUnlocked ? 0xFFFFFFFF : m_Permissions; - if (m_pEncryptDict && m_pEncryptDict->GetStringFor("Filter") == "Standard") { + if (m_pEncryptDict && + m_pEncryptDict->GetByteStringFor("Filter") == "Standard") { // See PDF Reference 1.7, page 123, table 3.20. dwPermission &= 0xFFFFFFFC; dwPermission |= 0xFFFFF0C0; @@ -225,21 +227,23 @@ static bool LoadCryptInfo(const CPDF_Dictionary* pEncryptDict, const ByteString& name, - int* cipher, + CPDF_CryptoHandler::Cipher* cipher, size_t* keylen_out) { int Version = pEncryptDict->GetIntegerFor("V"); - *cipher = FXCIPHER_RC4; + *cipher = CPDF_CryptoHandler::Cipher::kRC4; *keylen_out = 0; int keylen = 0; if (Version >= 4) { - const CPDF_Dictionary* pCryptFilters = pEncryptDict->GetDictFor("CF"); + RetainPtr<const CPDF_Dictionary> pCryptFilters = + pEncryptDict->GetDictFor("CF"); if (!pCryptFilters) return false; if (name == "Identity") { - *cipher = FXCIPHER_NONE; + *cipher = CPDF_CryptoHandler::Cipher::kNone; } else { - const CPDF_Dictionary* pDefFilter = pCryptFilters->GetDictFor(name); + RetainPtr<const CPDF_Dictionary> pDefFilter = + pCryptFilters->GetDictFor(name); if (!pDefFilter) return false; @@ -259,9 +263,9 @@ nKeyBits *= 8; } keylen = nKeyBits / 8; - ByteString cipher_name = pDefFilter->GetStringFor("CFM"); + ByteString cipher_name = pDefFilter->GetByteStringFor("CFM"); if (cipher_name == "AESV2" || cipher_name == "AESV3") - *cipher = FXCIPHER_AES; + *cipher = CPDF_CryptoHandler::Cipher::kAES; } } else { keylen = Version > 1 ? pEncryptDict->GetIntegerFor("Length", 40) / 8 : 5; @@ -284,8 +288,8 @@ if (m_Version < 4) return LoadCryptInfo(pEncryptDict, ByteString(), &m_Cipher, &m_KeyLen); - ByteString stmf_name = pEncryptDict->GetStringFor("StmF"); - ByteString strf_name = pEncryptDict->GetStringFor("StrF"); + ByteString stmf_name = pEncryptDict->GetByteStringFor("StmF"); + ByteString strf_name = pEncryptDict->GetByteStringFor("StrF"); if (stmf_name != strf_name) return false; @@ -293,7 +297,7 @@ } bool CPDF_SecurityHandler::LoadDict(const CPDF_Dictionary* pEncryptDict, - int* cipher, + CPDF_CryptoHandler::Cipher* cipher, size_t* key_len) { m_pEncryptDict.Reset(pEncryptDict); m_Version = pEncryptDict->GetIntegerFor("V"); @@ -303,8 +307,8 @@ ByteString strf_name; ByteString stmf_name; if (m_Version >= 4) { - stmf_name = pEncryptDict->GetStringFor("StmF"); - strf_name = pEncryptDict->GetStringFor("StrF"); + stmf_name = pEncryptDict->GetByteStringFor("StmF"); + strf_name = pEncryptDict->GetByteStringFor("StrF"); if (stmf_name != strf_name) return false; } @@ -318,14 +322,14 @@ bool CPDF_SecurityHandler::AES256_CheckPassword(const ByteString& password, bool bOwner) { - ASSERT(m_pEncryptDict); - ASSERT(m_Revision >= 5); + DCHECK(m_pEncryptDict); + DCHECK(m_Revision >= 5); - ByteString okey = m_pEncryptDict->GetStringFor("O"); + ByteString okey = m_pEncryptDict->GetByteStringFor("O"); if (okey.GetLength() < 48) return false; - ByteString ukey = m_pEncryptDict->GetStringFor("U"); + ByteString ukey = m_pEncryptDict->GetByteStringFor("U"); if (ukey.GetLength() < 48) return false; @@ -357,18 +361,18 @@ CRYPT_SHA256Update(&sha, ukey.raw_str(), 48); CRYPT_SHA256Finish(&sha, digest); } - ByteString ekey = m_pEncryptDict->GetStringFor(bOwner ? "OE" : "UE"); + ByteString ekey = m_pEncryptDict->GetByteStringFor(bOwner ? "OE" : "UE"); if (ekey.GetLength() < 32) return false; CRYPT_aes_context aes = {}; - CRYPT_AESSetKey(&aes, digest, sizeof(digest), false); + CRYPT_AESSetKey(&aes, digest, sizeof(digest)); uint8_t iv[16] = {}; CRYPT_AESSetIV(&aes, iv); CRYPT_AESDecrypt(&aes, m_EncryptKey, ekey.raw_str(), 32); - CRYPT_AESSetKey(&aes, m_EncryptKey, sizeof(m_EncryptKey), false); + CRYPT_AESSetKey(&aes, m_EncryptKey, sizeof(m_EncryptKey)); CRYPT_AESSetIV(&aes, iv); - ByteString perms = m_pEncryptDict->GetStringFor("Perms"); + ByteString perms = m_pEncryptDict->GetByteStringFor("Perms"); if (perms.IsEmpty()) return false; @@ -381,7 +385,7 @@ if (buf[9] != 'a' || buf[10] != 'd' || buf[11] != 'b') return false; - if (FXDWORD_GET_LSBFIRST(buf) != m_Permissions) + if (FXSYS_UINT32_GET_LSBFIRST(buf) != m_Permissions) return false; // Relax this check as there appear to be some non-conforming documents @@ -437,7 +441,7 @@ CalcEncryptKey(m_pEncryptDict.Get(), password, m_EncryptKey, m_KeyLen, bIgnoreEncryptMeta, m_FileId); ByteString ukey = - m_pEncryptDict ? m_pEncryptDict->GetStringFor("U") : ByteString(); + m_pEncryptDict ? m_pEncryptDict->GetByteStringFor("U") : ByteString(); if (ukey.GetLength() < 16) { return false; } @@ -470,7 +474,7 @@ ByteString CPDF_SecurityHandler::GetUserPassword( const ByteString& owner_password) const { constexpr size_t kRequiredOkeyLength = 32; - ByteString okey = m_pEncryptDict->GetStringFor("O"); + ByteString okey = m_pEncryptDict->GetByteStringFor("O"); size_t okeylen = std::min<size_t>(okey.GetLength(), kRequiredOkeyLength); if (okeylen < kRequiredOkeyLength) return ByteString(); @@ -539,9 +543,9 @@ const ByteString& user_password, const ByteString& owner_password, bool bDefault) { - ASSERT(pEncryptDict); + DCHECK(pEncryptDict); - int cipher = FXCIPHER_NONE; + CPDF_CryptoHandler::Cipher cipher = CPDF_CryptoHandler::Cipher::kNone; size_t key_len = 0; if (!LoadDict(pEncryptDict, &cipher, &key_len)) { return; @@ -552,7 +556,7 @@ if (m_Revision >= 5) { uint32_t random[4]; - FX_Random_GenerateMT(random, FX_ArraySize(random)); + FX_Random_GenerateMT(random, std::size(random)); CRYPT_sha2_context sha; CRYPT_SHA256Start(&sha); CRYPT_SHA256Update(&sha, reinterpret_cast<uint8_t*>(random), @@ -590,7 +594,7 @@ ByteString file_id; if (pIdArray) - file_id = pIdArray->GetStringAt(0); + file_id = pIdArray->GetByteStringAt(0); CalcEncryptKey(m_pEncryptDict.Get(), user_password, m_EncryptKey, key_len, false, file_id); @@ -646,7 +650,7 @@ uint8_t digest[20]; CRYPT_SHA1Finish(&sha, digest); - ByteString ukey = pEncryptDict->GetStringFor("U"); + ByteString ukey = pEncryptDict->GetByteStringFor("U"); CRYPT_sha2_context sha2; uint8_t digest1[48]; if (m_Revision >= 6) { @@ -677,7 +681,7 @@ CRYPT_SHA256Finish(&sha2, digest1); } CRYPT_aes_context aes = {}; - CRYPT_AESSetKey(&aes, digest1, 32, true); + CRYPT_AESSetKey(&aes, digest1, 32); uint8_t iv[16] = {}; CRYPT_AESSetIV(&aes, iv); CRYPT_AESEncrypt(&aes, digest1, m_EncryptKey, sizeof(m_EncryptKey)); @@ -706,7 +710,7 @@ FX_Random_GenerateMT(buf_random, 1); CRYPT_aes_context aes = {}; - CRYPT_AESSetKey(&aes, m_EncryptKey, sizeof(m_EncryptKey), true); + CRYPT_AESSetKey(&aes, m_EncryptKey, sizeof(m_EncryptKey)); uint8_t iv[16] = {}; CRYPT_AESSetIV(&aes, iv); @@ -718,5 +722,5 @@ void CPDF_SecurityHandler::InitCryptoHandler() { m_pCryptoHandler = - pdfium::MakeUnique<CPDF_CryptoHandler>(m_Cipher, m_EncryptKey, m_KeyLen); + std::make_unique<CPDF_CryptoHandler>(m_Cipher, m_EncryptKey, m_KeyLen); }
diff --git a/core/fpdfapi/parser/cpdf_security_handler.h b/core/fpdfapi/parser/cpdf_security_handler.h index 05eb689..300dd9b 100644 --- a/core/fpdfapi/parser/cpdf_security_handler.h +++ b/core/fpdfapi/parser/cpdf_security_handler.h
@@ -1,4 +1,4 @@ -// Copyright 2016 PDFium Authors. All rights reserved. +// Copyright 2016 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -7,29 +7,24 @@ #ifndef CORE_FPDFAPI_PARSER_CPDF_SECURITY_HANDLER_H_ #define CORE_FPDFAPI_PARSER_CPDF_SECURITY_HANDLER_H_ +#include <stddef.h> +#include <stdint.h> + #include <memory> -#include "core/fxcrt/fx_string.h" -#include "core/fxcrt/fx_system.h" +#include "core/fpdfapi/parser/cpdf_crypto_handler.h" +#include "core/fxcrt/bytestring.h" #include "core/fxcrt/retain_ptr.h" -#define FXCIPHER_NONE 0 -#define FXCIPHER_RC4 1 -#define FXCIPHER_AES 2 -#define FXCIPHER_AES2 3 - class CPDF_Array; -class CPDF_CryptoHandler; class CPDF_Dictionary; -class CPDF_Parser; -class CPDF_SecurityHandler : public Retainable { +class CPDF_SecurityHandler final : public Retainable { public: - template <typename T, typename... Args> - friend RetainPtr<T> pdfium::MakeRetain(Args&&... args); + CONSTRUCT_VIA_MAKE_RETAIN; bool OnInit(const CPDF_Dictionary* pEncryptDict, - const CPDF_Array* pIdArray, + RetainPtr<const CPDF_Array> pIdArray, const ByteString& password); void OnCreate(CPDF_Dictionary* pEncryptDict, const CPDF_Array* pIdArray, @@ -63,7 +58,7 @@ bool LoadDict(const CPDF_Dictionary* pEncryptDict); bool LoadDict(const CPDF_Dictionary* pEncryptDict, - int* cipher, + CPDF_CryptoHandler::Cipher* cipher, size_t* key_len); ByteString GetUserPassword(const ByteString& owner_password) const; @@ -89,13 +84,13 @@ int m_Version = 0; int m_Revision = 0; uint32_t m_Permissions = 0; - int m_Cipher = FXCIPHER_NONE; size_t m_KeyLen = 0; + CPDF_CryptoHandler::Cipher m_Cipher = CPDF_CryptoHandler::Cipher::kNone; PasswordEncodingConversion m_PasswordEncodingConversion = kUnknown; ByteString m_FileId; RetainPtr<const CPDF_Dictionary> m_pEncryptDict; std::unique_ptr<CPDF_CryptoHandler> m_pCryptoHandler; - uint8_t m_EncryptKey[32]; + uint8_t m_EncryptKey[32] = {}; }; #endif // CORE_FPDFAPI_PARSER_CPDF_SECURITY_HANDLER_H_
diff --git a/core/fpdfapi/parser/cpdf_security_handler_embeddertest.cpp b/core/fpdfapi/parser/cpdf_security_handler_embeddertest.cpp index ee2a621..f2c5ac1 100644 --- a/core/fpdfapi/parser/cpdf_security_handler_embeddertest.cpp +++ b/core/fpdfapi/parser/cpdf_security_handler_embeddertest.cpp
@@ -1,8 +1,7 @@ -// Copyright 2016 PDFium Authors. All rights reserved. +// Copyright 2016 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include <memory> #include <string> #include "build/build_config.h" @@ -10,11 +9,13 @@ #include "core/fpdfapi/parser/cpdf_document.h" #include "core/fpdfapi/parser/cpdf_parser.h" #include "core/fxcrt/fx_system.h" +#include "core/fxge/cfx_defaultrenderdevice.h" #include "public/cpp/fpdf_scopers.h" #include "public/fpdf_edit.h" #include "public/fpdf_save.h" #include "public/fpdfview.h" #include "testing/embedder_test.h" +#include "testing/embedder_test_constants.h" #include "testing/gtest/include/gtest/gtest.h" namespace { @@ -92,31 +93,16 @@ void VerifyHelloWorldPage(FPDF_PAGE page) { ASSERT_TRUE(page); -#if defined(OS_WIN) - const char kExpectedHash[] = "795b7ce1626931aa06af0fa23b7d80bb"; -#elif defined(OS_MACOSX) - const char kExpectedHash[] = "b90475ca64d1348c3bf5e2b77ad9187a"; -#else - const char kExpectedHash[] = "2baa4c0e1758deba1b9c908e1fbd04ed"; -#endif - ScopedFPDFBitmap page_bitmap = RenderPage(page); - CompareBitmap(page_bitmap.get(), 200, 200, kExpectedHash); + CompareBitmap(page_bitmap.get(), 200, 200, pdfium::HelloWorldChecksum()); } void VerifyModifiedHelloWorldPage(FPDF_PAGE page) { ASSERT_TRUE(page); -#if defined(OS_WIN) - const char kExpectedHash[] = "93db13099042bafefb3c22a165bad684"; -#elif defined(OS_MACOSX) - const char kExpectedHash[] = "f8fbd14a048b9e2ea8e5f059f22a910e"; -#else - const char kExpectedHash[] = "93dcc09055f87a2792c8e3065af99a1b"; -#endif - ScopedFPDFBitmap page_bitmap = RenderPage(page); - CompareBitmap(page_bitmap.get(), 200, 200, kExpectedHash); + CompareBitmap(page_bitmap.get(), 200, 200, + pdfium::HelloWorldRemovedChecksum()); } }; @@ -148,20 +134,16 @@ EXPECT_EQ(0xFFFFFFFC, FPDF_GetDocPermissions(document())); } -// TODO(crbug.com/pdfium/11): Fix this test and enable. -#if defined(_SKIA_SUPPORT_) || defined(_SKIA_SUPPORT_PATHS_) -#define MAYBE_PasswordAfterGenerateSave DISABLED_PasswordAfterGenerateSave +TEST_F(CPDFSecurityHandlerEmbedderTest, PasswordAfterGenerateSave) { + const char* checksum = []() { + if (CFX_DefaultRenderDevice::SkiaIsDefaultRenderer()) + return "df9fe67555b7ceb59c99036e8d2c1c76"; +#if BUILDFLAG(IS_APPLE) + return "2a308e8cc20a6221112c387d122075a8"; #else -#define MAYBE_PasswordAfterGenerateSave PasswordAfterGenerateSave -#endif -TEST_F(CPDFSecurityHandlerEmbedderTest, MAYBE_PasswordAfterGenerateSave) { -#if _FX_PLATFORM_ == _FX_PLATFORM_LINUX_ - const char md5[] = "7048dca58e2ed8f93339008b91e4eb4e"; -#elif defined(OS_MACOSX) - const char md5[] = "6951b6c9891dfe0332a5b1983e484400"; -#else - const char md5[] = "041c2fb541c8907cc22ce101b686c79e"; -#endif // _FX_PLATFORM_ == _FX_PLATFORM_LINUX_ + return "9fe7eef8e51d15a604001854be6ed1ee"; +#endif // BUILDFLAG(IS_APPLE) + }(); { ASSERT_TRUE(OpenDocumentWithOptions("encrypted.pdf", "5678", LinearizeOption::kMustLinearize, @@ -174,7 +156,7 @@ EXPECT_TRUE(FPDFPath_SetDrawMode(red_rect, FPDF_FILLMODE_ALTERNATE, 0)); FPDFPage_InsertObject(page, red_rect); ScopedFPDFBitmap bitmap = RenderLoadedPage(page); - CompareBitmap(bitmap.get(), 612, 792, md5); + CompareBitmap(bitmap.get(), 612, 792, checksum); EXPECT_TRUE(FPDFPage_GenerateContent(page)); SetWholeFileAvailable(); EXPECT_TRUE(FPDF_SaveAsCopy(document(), this, 0)); @@ -196,8 +178,9 @@ for (const auto& test : tests) { ASSERT_TRUE(OpenSavedDocumentWithPassword(test.password)); FPDF_PAGE page = LoadSavedPage(0); - VerifySavedRendering(page, 612, 792, md5); - EXPECT_EQ(test.permissions, FPDF_GetDocPermissions(saved_document_)); + ASSERT_TRUE(page); + VerifySavedRendering(page, 612, 792, checksum); + EXPECT_EQ(test.permissions, FPDF_GetDocPermissions(saved_document())); CloseSavedPage(page); CloseSavedDocument(); @@ -679,3 +662,7 @@ VerifySavedModifiedHelloWorldDocumentWithPassword(kHotelLatin1); VerifySavedModifiedHelloWorldDocumentWithPassword(kHotelUTF8); } + +TEST_F(CPDFSecurityHandlerEmbedderTest, Bug1124998) { + OpenAndVerifyHelloWorldDocumentWithPassword("bug_1124998.pdf", "test"); +}
diff --git a/core/fpdfapi/parser/cpdf_seekablemultistream.cpp b/core/fpdfapi/parser/cpdf_seekablemultistream.cpp index d2a0417..bad6d97 100644 --- a/core/fpdfapi/parser/cpdf_seekablemultistream.cpp +++ b/core/fpdfapi/parser/cpdf_seekablemultistream.cpp
@@ -1,4 +1,4 @@ -// Copyright 2017 PDFium Authors. All rights reserved. +// Copyright 2017 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -7,32 +7,35 @@ #include "core/fpdfapi/parser/cpdf_seekablemultistream.h" #include <algorithm> +#include <utility> +#include "core/fpdfapi/parser/cpdf_stream.h" #include "core/fpdfapi/parser/cpdf_stream_acc.h" -#include "third_party/base/logging.h" -#include "third_party/base/stl_util.h" +#include "core/fxcrt/fx_safe_types.h" +#include "core/fxcrt/span_util.h" +#include "core/fxcrt/stl_util.h" +#include "third_party/base/notreached.h" CPDF_SeekableMultiStream::CPDF_SeekableMultiStream( - const std::vector<const CPDF_Stream*>& streams) { - for (const CPDF_Stream* pStream : streams) { - m_Data.push_back(pdfium::MakeRetain<CPDF_StreamAcc>(pStream)); + std::vector<RetainPtr<const CPDF_Stream>> streams) { + for (auto& pStream : streams) { + m_Data.push_back(pdfium::MakeRetain<CPDF_StreamAcc>(std::move(pStream))); m_Data.back()->LoadAllDataFiltered(); } } -CPDF_SeekableMultiStream::~CPDF_SeekableMultiStream() {} +CPDF_SeekableMultiStream::~CPDF_SeekableMultiStream() = default; FX_FILESIZE CPDF_SeekableMultiStream::GetSize() { - uint32_t dwSize = 0; + FX_SAFE_FILESIZE dwSize = 0; for (const auto& acc : m_Data) dwSize += acc->GetSize(); - return dwSize; + return dwSize.ValueOrDie(); } -bool CPDF_SeekableMultiStream::ReadBlockAtOffset(void* buffer, - FX_FILESIZE offset, - size_t size) { - int32_t iCount = pdfium::CollectionSize<int32_t>(m_Data); +bool CPDF_SeekableMultiStream::ReadBlockAtOffset(pdfium::span<uint8_t> buffer, + FX_FILESIZE offset) { + int32_t iCount = fxcrt::CollectionSize<int32_t>(m_Data); int32_t index = 0; while (index < iCount) { const auto& acc = m_Data[index]; @@ -44,22 +47,20 @@ index++; } while (index < iCount) { - const auto& acc = m_Data[index]; - uint32_t dwSize = acc->GetSize(); - size_t dwRead = std::min(size, static_cast<size_t>(dwSize - offset)); - memcpy(buffer, acc->GetSpan().subspan(offset, dwRead).data(), dwRead); - size -= dwRead; - if (size == 0) + auto acc_span = m_Data[index]->GetSpan(); + size_t dwRead = std::min<size_t>(buffer.size(), acc_span.size() - offset); + fxcrt::spancpy(buffer, acc_span.subspan(offset, dwRead)); + buffer = buffer.subspan(dwRead); + if (buffer.empty()) return true; - buffer = static_cast<uint8_t*>(buffer) + dwRead; offset = 0; index++; } return false; } -size_t CPDF_SeekableMultiStream::ReadBlock(void* buffer, size_t size) { +size_t CPDF_SeekableMultiStream::ReadBlock(pdfium::span<uint8_t> buffer) { NOTREACHED(); return 0; } @@ -77,9 +78,9 @@ return false; } -bool CPDF_SeekableMultiStream::WriteBlockAtOffset(const void* pData, - FX_FILESIZE offset, - size_t size) { +bool CPDF_SeekableMultiStream::WriteBlockAtOffset( + pdfium::span<const uint8_t> buffer, + FX_FILESIZE offset) { NOTREACHED(); return false; }
diff --git a/core/fpdfapi/parser/cpdf_seekablemultistream.h b/core/fpdfapi/parser/cpdf_seekablemultistream.h index 30a8479..fc659a6 100644 --- a/core/fpdfapi/parser/cpdf_seekablemultistream.h +++ b/core/fpdfapi/parser/cpdf_seekablemultistream.h
@@ -1,4 +1,4 @@ -// Copyright 2017 PDFium Authors. All rights reserved. +// Copyright 2017 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -18,21 +18,19 @@ class CPDF_SeekableMultiStream final : public IFX_SeekableStream { public: explicit CPDF_SeekableMultiStream( - const std::vector<const CPDF_Stream*>& streams); + std::vector<RetainPtr<const CPDF_Stream>> streams); ~CPDF_SeekableMultiStream() override; - // IFX_SeekableReadStream + // IFX_SeekableReadStream: FX_FILESIZE GetPosition() override; FX_FILESIZE GetSize() override; - bool ReadBlockAtOffset(void* buffer, - FX_FILESIZE offset, - size_t size) override; - size_t ReadBlock(void* buffer, size_t size) override; bool IsEOF() override; + size_t ReadBlock(pdfium::span<uint8_t> buffer) override; + bool ReadBlockAtOffset(pdfium::span<uint8_t> buffer, + FX_FILESIZE offset) override; + bool WriteBlockAtOffset(pdfium::span<const uint8_t> buffer, + FX_FILESIZE offset) override; bool Flush() override; - bool WriteBlockAtOffset(const void* pData, - FX_FILESIZE offset, - size_t size) override; private: std::vector<RetainPtr<CPDF_StreamAcc>> m_Data;
diff --git a/core/fpdfapi/parser/cpdf_seekablemultistream_unittest.cpp b/core/fpdfapi/parser/cpdf_seekablemultistream_unittest.cpp index 4f806fa..5e63db0 100644 --- a/core/fpdfapi/parser/cpdf_seekablemultistream_unittest.cpp +++ b/core/fpdfapi/parser/cpdf_seekablemultistream_unittest.cpp
@@ -1,85 +1,91 @@ -// Copyright 2016 PDFium Authors. All rights reserved. +// Copyright 2016 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "core/fpdfapi/parser/cpdf_seekablemultistream.h" -#include <memory> +#include <utility> #include <vector> #include "core/fpdfapi/parser/cpdf_dictionary.h" #include "core/fpdfapi/parser/cpdf_stream.h" +#include "core/fxcrt/data_vector.h" #include "testing/gtest/include/gtest/gtest.h" -#include "third_party/base/ptr_util.h" TEST(CPDFSeekableMultiStreamTest, NoStreams) { - std::vector<const CPDF_Stream*> streams; - auto fileread = pdfium::MakeRetain<CPDF_SeekableMultiStream>(streams); + std::vector<RetainPtr<const CPDF_Stream>> streams; + auto fileread = + pdfium::MakeRetain<CPDF_SeekableMultiStream>(std::move(streams)); uint8_t output_buffer[16]; memset(output_buffer, 0xbd, sizeof(output_buffer)); - EXPECT_FALSE(fileread->ReadBlockAtOffset(output_buffer, 0, 0)); + EXPECT_FALSE(fileread->ReadBlockAtOffset({output_buffer, 0}, 0)); EXPECT_EQ(0xbd, output_buffer[0]); } TEST(CXFAFileReadTest, EmptyStreams) { - std::vector<const CPDF_Stream*> streams; - auto stream1 = pdfium::MakeRetain<CPDF_Stream>(); - streams.push_back(stream1.Get()); - auto fileread = pdfium::MakeRetain<CPDF_SeekableMultiStream>(streams); + std::vector<RetainPtr<const CPDF_Stream>> streams; + streams.push_back(pdfium::MakeRetain<CPDF_Stream>()); + auto fileread = + pdfium::MakeRetain<CPDF_SeekableMultiStream>(std::move(streams)); uint8_t output_buffer[16]; memset(output_buffer, 0xbd, sizeof(output_buffer)); - EXPECT_FALSE(fileread->ReadBlockAtOffset(output_buffer, 0, 0)); + EXPECT_FALSE(fileread->ReadBlockAtOffset({output_buffer, 0}, 0)); EXPECT_EQ(0xbd, output_buffer[0]); } TEST(CXFAFileReadTest, NormalStreams) { - std::vector<const CPDF_Stream*> streams; - auto stream1 = pdfium::MakeRetain<CPDF_Stream>(); - auto stream2 = pdfium::MakeRetain<CPDF_Stream>(); - auto stream3 = pdfium::MakeRetain<CPDF_Stream>(); - // 16 chars total. - stream1->InitStream(ByteStringView("one t").raw_span(), - pdfium::MakeRetain<CPDF_Dictionary>()); - stream2->InitStream(ByteStringView("wo ").raw_span(), - pdfium::MakeRetain<CPDF_Dictionary>()); - stream3->InitStream(ByteStringView("three!!!").raw_span(), - pdfium::MakeRetain<CPDF_Dictionary>()); + static const char kOne[] = "one t"; + static const char kTwo[] = "wo "; + static const char kThree[] = "three!!!"; - streams.push_back(stream1.Get()); - streams.push_back(stream2.Get()); - streams.push_back(stream3.Get()); - auto fileread = pdfium::MakeRetain<CPDF_SeekableMultiStream>(streams); + ByteStringView one_view(kOne); + ByteStringView two_view(kTwo); + ByteStringView three_view(kThree); + auto stream1 = pdfium::MakeRetain<CPDF_Stream>( + DataVector<uint8_t>(one_view.begin(), one_view.end()), + pdfium::MakeRetain<CPDF_Dictionary>()); + auto stream2 = pdfium::MakeRetain<CPDF_Stream>( + DataVector<uint8_t>(two_view.begin(), two_view.end()), + pdfium::MakeRetain<CPDF_Dictionary>()); + auto stream3 = pdfium::MakeRetain<CPDF_Stream>( + DataVector<uint8_t>(three_view.begin(), three_view.end()), + pdfium::MakeRetain<CPDF_Dictionary>()); + + std::vector<RetainPtr<const CPDF_Stream>> streams; + streams.push_back(std::move(stream1)); + streams.push_back(std::move(stream2)); + streams.push_back(std::move(stream3)); + auto fileread = + pdfium::MakeRetain<CPDF_SeekableMultiStream>(std::move(streams)); uint8_t output_buffer[16]; memset(output_buffer, 0xbd, sizeof(output_buffer)); - EXPECT_TRUE(fileread->ReadBlockAtOffset(output_buffer, 0, 0)); + EXPECT_TRUE(fileread->ReadBlockAtOffset({output_buffer, 0}, 0)); EXPECT_EQ(0xbd, output_buffer[0]); memset(output_buffer, 0xbd, sizeof(output_buffer)); - EXPECT_TRUE(fileread->ReadBlockAtOffset(output_buffer, 1, 0)); + EXPECT_TRUE(fileread->ReadBlockAtOffset({output_buffer, 0}, 1)); EXPECT_EQ(0xbd, output_buffer[0]); memset(output_buffer, 0xbd, sizeof(output_buffer)); - EXPECT_TRUE(fileread->ReadBlockAtOffset(output_buffer, 0, 1)); + EXPECT_TRUE(fileread->ReadBlockAtOffset({output_buffer, 1}, 0)); EXPECT_EQ(0, memcmp(output_buffer, "o", 1)); EXPECT_EQ(0xbd, output_buffer[1]); memset(output_buffer, 0xbd, sizeof(output_buffer)); - EXPECT_TRUE( - fileread->ReadBlockAtOffset(output_buffer, 0, sizeof(output_buffer))); + EXPECT_TRUE(fileread->ReadBlockAtOffset(output_buffer, 0)); EXPECT_EQ(0, memcmp(output_buffer, "one two three!!!", 16)); memset(output_buffer, 0xbd, sizeof(output_buffer)); - EXPECT_TRUE(fileread->ReadBlockAtOffset(output_buffer, 2, 10)); + EXPECT_TRUE(fileread->ReadBlockAtOffset({output_buffer, 10}, 2)); EXPECT_EQ(0, memcmp(output_buffer, "e two thre", 10)); EXPECT_EQ(0xbd, output_buffer[11]); memset(output_buffer, 0xbd, sizeof(output_buffer)); - EXPECT_FALSE( - fileread->ReadBlockAtOffset(output_buffer, 1, sizeof(output_buffer))); + EXPECT_FALSE(fileread->ReadBlockAtOffset(output_buffer, 1)); EXPECT_EQ(0, memcmp(output_buffer, "ne two three!!!", 15)); EXPECT_EQ(0xbd, output_buffer[15]); }
diff --git a/core/fpdfapi/parser/cpdf_simple_parser.cpp b/core/fpdfapi/parser/cpdf_simple_parser.cpp index ff6e2cf..ce09904 100644 --- a/core/fpdfapi/parser/cpdf_simple_parser.cpp +++ b/core/fpdfapi/parser/cpdf_simple_parser.cpp
@@ -1,4 +1,4 @@ -// Copyright 2016 PDFium Authors. All rights reserved. +// Copyright 2016 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -17,7 +17,7 @@ uint8_t ch; // Skip whitespace and comment lines. - while (1) { + while (true) { if (data_.size() <= cur_pos_) return ByteStringView(); @@ -31,7 +31,7 @@ if (ch != '%') break; - while (1) { + while (true) { if (data_.size() <= cur_pos_) return ByteStringView(); @@ -46,7 +46,7 @@ if (PDFCharIsDelimiter(ch)) { // Find names if (ch == '/') { - while (1) { + while (true) { if (data_.size() <= cur_pos_) break;
diff --git a/core/fpdfapi/parser/cpdf_simple_parser.h b/core/fpdfapi/parser/cpdf_simple_parser.h index f9461b6..e4bf0c0 100644 --- a/core/fpdfapi/parser/cpdf_simple_parser.h +++ b/core/fpdfapi/parser/cpdf_simple_parser.h
@@ -1,4 +1,4 @@ -// Copyright 2016 PDFium Authors. All rights reserved. +// Copyright 2016 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -7,8 +7,9 @@ #ifndef CORE_FPDFAPI_PARSER_CPDF_SIMPLE_PARSER_H_ #define CORE_FPDFAPI_PARSER_CPDF_SIMPLE_PARSER_H_ -#include "core/fxcrt/fx_string.h" -#include "core/fxcrt/fx_system.h" +#include <stdint.h> + +#include "core/fxcrt/bytestring.h" #include "third_party/base/span.h" class CPDF_SimpleParser {
diff --git a/core/fpdfapi/parser/cpdf_simple_parser_unittest.cpp b/core/fpdfapi/parser/cpdf_simple_parser_unittest.cpp index 5834d77..965d577 100644 --- a/core/fpdfapi/parser/cpdf_simple_parser_unittest.cpp +++ b/core/fpdfapi/parser/cpdf_simple_parser_unittest.cpp
@@ -1,10 +1,10 @@ -// Copyright 2016 PDFium Authors. All rights reserved. +// Copyright 2016 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "core/fpdfapi/parser/cpdf_simple_parser.h" -#include <string> +#include <iterator> #include "core/fpdfapi/parser/fpdf_parser_utility.h" #include "testing/gtest/include/gtest/gtest.h" @@ -50,7 +50,7 @@ STR_IN_OUT_CASE(" $^&&*\t\0sdff ", "$^&&*"), STR_IN_OUT_CASE("\n\r+3.5656 -11.0", "+3.5656"), }; - for (size_t i = 0; i < FX_ArraySize(test_data); ++i) { + for (size_t i = 0; i < std::size(test_data); ++i) { const pdfium::StrFuncTestData& data = test_data[i]; CPDF_SimpleParser parser(pdfium::make_span(data.input, data.input_size)); ByteStringView word = parser.GetWord();
diff --git a/core/fpdfapi/parser/cpdf_stream.cpp b/core/fpdfapi/parser/cpdf_stream.cpp index 4b5ef5c..fa08ffa 100644 --- a/core/fpdfapi/parser/cpdf_stream.cpp +++ b/core/fpdfapi/parser/cpdf_stream.cpp
@@ -1,4 +1,4 @@ -// Copyright 2016 PDFium Authors. All rights reserved. +// Copyright 2016 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -6,8 +6,10 @@ #include "core/fpdfapi/parser/cpdf_stream.h" +#include <stdint.h> + +#include <sstream> #include <utility> -#include <vector> #include "constants/stream_dict_common.h" #include "core/fpdfapi/parser/cpdf_dictionary.h" @@ -16,74 +18,64 @@ #include "core/fpdfapi/parser/cpdf_number.h" #include "core/fpdfapi/parser/cpdf_stream_acc.h" #include "core/fpdfapi/parser/fpdf_parser_decode.h" +#include "core/fpdfapi/parser/fpdf_parser_utility.h" +#include "core/fxcrt/cfx_memorystream.h" +#include "core/fxcrt/data_vector.h" #include "core/fxcrt/fx_stream.h" +#include "core/fxcrt/span_util.h" +#include "third_party/base/containers/contains.h" #include "third_party/base/numerics/safe_conversions.h" -#include "third_party/base/ptr_util.h" -#include "third_party/base/stl_util.h" namespace { bool IsMetaDataStreamDictionary(const CPDF_Dictionary* dict) { - return dict && dict->GetStringFor("Type") == "Metadata" && - dict->GetStringFor("Subtype") == "XML"; + // See ISO 32000-1:2008 spec, table 315. + return ValidateDictType(dict, "Metadata") && + dict->GetNameFor("Subtype") == "XML"; } } // namespace -CPDF_Stream::CPDF_Stream() {} +CPDF_Stream::CPDF_Stream() = default; -CPDF_Stream::CPDF_Stream(std::unique_ptr<uint8_t, FxFreeDeleter> pData, - uint32_t size, +CPDF_Stream::CPDF_Stream(RetainPtr<CPDF_Dictionary> pDict) + : CPDF_Stream(DataVector<uint8_t>(), std::move(pDict)) {} + +CPDF_Stream::CPDF_Stream(DataVector<uint8_t> pData, RetainPtr<CPDF_Dictionary> pDict) - : m_pDict(std::move(pDict)) { - TakeData(std::move(pData), size); + : data_(std::move(pData)), dict_(std::move(pDict)) { + SetLengthInDict(pdfium::base::checked_cast<int>( + absl::get<DataVector<uint8_t>>(data_).size())); } CPDF_Stream::~CPDF_Stream() { m_ObjNum = kInvalidObjNum; - if (m_pDict && m_pDict->GetObjNum() == kInvalidObjNum) - m_pDict.Leak(); // lowercase release, release ownership. + if (dict_ && dict_->GetObjNum() == kInvalidObjNum) + dict_.Leak(); // lowercase release, release ownership. } CPDF_Object::Type CPDF_Stream::GetType() const { return kStream; } -CPDF_Dictionary* CPDF_Stream::GetDict() { - return m_pDict.Get(); +const CPDF_Dictionary* CPDF_Stream::GetDictInternal() const { + return dict_.Get(); } -const CPDF_Dictionary* CPDF_Stream::GetDict() const { - return m_pDict.Get(); -} - -bool CPDF_Stream::IsStream() const { - return true; -} - -CPDF_Stream* CPDF_Stream::AsStream() { +CPDF_Stream* CPDF_Stream::AsMutableStream() { return this; } -const CPDF_Stream* CPDF_Stream::AsStream() const { - return this; +void CPDF_Stream::InitStreamWithEmptyData(RetainPtr<CPDF_Dictionary> pDict) { + dict_ = std::move(pDict); + TakeData({}); } -void CPDF_Stream::InitStream(pdfium::span<const uint8_t> pData, - RetainPtr<CPDF_Dictionary> pDict) { - m_pDict = std::move(pDict); - SetData(pData); -} - -void CPDF_Stream::InitStreamFromFile( - const RetainPtr<IFX_SeekableReadStream>& pFile, - RetainPtr<CPDF_Dictionary> pDict) { - m_bMemoryBased = false; - m_pDataBuf.reset(); - m_pFile = pFile; - m_dwSize = pdfium::base::checked_cast<uint32_t>(pFile->GetSize()); - m_pDict = std::move(pDict); - m_pDict->SetNewFor<CPDF_Number>("Length", static_cast<int>(m_dwSize)); +void CPDF_Stream::InitStreamFromFile(RetainPtr<IFX_SeekableReadStream> pFile, + RetainPtr<CPDF_Dictionary> pDict) { + data_ = pFile; + dict_ = std::move(pDict); + SetLengthInDict(pdfium::base::checked_cast<int>(pFile->GetSize())); } RetainPtr<CPDF_Object> CPDF_Stream::Clone() const { @@ -94,29 +86,27 @@ bool bDirect, std::set<const CPDF_Object*>* pVisited) const { pVisited->insert(this); - auto pAcc = pdfium::MakeRetain<CPDF_StreamAcc>(this); + auto pAcc = pdfium::MakeRetain<CPDF_StreamAcc>(pdfium::WrapRetain(this)); pAcc->LoadAllDataRaw(); - uint32_t streamSize = pAcc->GetSize(); - const CPDF_Dictionary* pDict = GetDict(); + RetainPtr<const CPDF_Dictionary> pDict = GetDict(); RetainPtr<CPDF_Dictionary> pNewDict; - if (pDict && !pdfium::ContainsKey(*pVisited, pDict)) { - pNewDict = - ToDictionary(static_cast<const CPDF_Object*>(pDict)->CloneNonCyclic( - bDirect, pVisited)); + if (pDict && !pdfium::Contains(*pVisited, pDict.Get())) { + pNewDict = ToDictionary(static_cast<const CPDF_Object*>(pDict.Get()) + ->CloneNonCyclic(bDirect, pVisited)); } - return pdfium::MakeRetain<CPDF_Stream>(pAcc->DetachData(), streamSize, + return pdfium::MakeRetain<CPDF_Stream>(pAcc->DetachData(), std::move(pNewDict)); } void CPDF_Stream::SetDataAndRemoveFilter(pdfium::span<const uint8_t> pData) { SetData(pData); - m_pDict->RemoveFor("Filter"); - m_pDict->RemoveFor(pdfium::stream::kDecodeParms); + dict_->RemoveFor("Filter"); + dict_->RemoveFor(pdfium::stream::kDecodeParms); } void CPDF_Stream::SetDataFromStringstreamAndRemoveFilter( - std::ostringstream* stream) { + fxcrt::ostringstream* stream) { if (stream->tellp() <= 0) { SetDataAndRemoveFilter({}); return; @@ -128,26 +118,17 @@ } void CPDF_Stream::SetData(pdfium::span<const uint8_t> pData) { - std::unique_ptr<uint8_t, FxFreeDeleter> data_copy; - if (!pData.empty()) { - data_copy.reset(FX_Alloc(uint8_t, pData.size())); - memcpy(data_copy.get(), pData.data(), pData.size()); - } - TakeData(std::move(data_copy), pData.size()); + DataVector<uint8_t> data_copy(pData.begin(), pData.end()); + TakeData(std::move(data_copy)); } -void CPDF_Stream::TakeData(std::unique_ptr<uint8_t, FxFreeDeleter> pData, - uint32_t size) { - m_bMemoryBased = true; - m_pFile = nullptr; - m_pDataBuf = std::move(pData); - m_dwSize = size; - if (!m_pDict) - m_pDict = pdfium::MakeRetain<CPDF_Dictionary>(); - m_pDict->SetNewFor<CPDF_Number>("Length", static_cast<int>(size)); +void CPDF_Stream::TakeData(DataVector<uint8_t> data) { + const size_t size = data.size(); + data_ = std::move(data); + SetLengthInDict(pdfium::base::checked_cast<int>(size)); } -void CPDF_Stream::SetDataFromStringstream(std::ostringstream* stream) { +void CPDF_Stream::SetDataFromStringstream(fxcrt::ostringstream* stream) { if (stream->tellp() <= 0) { SetData({}); return; @@ -156,59 +137,72 @@ static_cast<size_t>(stream->tellp())}); } -bool CPDF_Stream::ReadRawData(FX_FILESIZE offset, - uint8_t* buf, - uint32_t size) const { - if (!m_bMemoryBased && m_pFile) - return m_pFile->ReadBlockAtOffset(buf, offset, size); +DataVector<uint8_t> CPDF_Stream::ReadAllRawData() const { + CHECK(IsFileBased()); - if (m_pDataBuf) - memcpy(buf, m_pDataBuf.get() + offset, size); + DataVector<uint8_t> result(GetRawSize()); + DCHECK(!result.empty()); - return true; + auto underlying_stream = absl::get<RetainPtr<IFX_SeekableReadStream>>(data_); + if (!underlying_stream->ReadBlockAtOffset(result, 0)) + return DataVector<uint8_t>(); + + return result; } bool CPDF_Stream::HasFilter() const { - return m_pDict && m_pDict->KeyExist("Filter"); + return dict_ && dict_->KeyExist("Filter"); } WideString CPDF_Stream::GetUnicodeText() const { - auto pAcc = pdfium::MakeRetain<CPDF_StreamAcc>(this); + auto pAcc = pdfium::MakeRetain<CPDF_StreamAcc>(pdfium::WrapRetain(this)); pAcc->LoadAllDataFiltered(); return PDF_DecodeText(pAcc->GetSpan()); } bool CPDF_Stream::WriteTo(IFX_ArchiveStream* archive, const CPDF_Encryptor* encryptor) const { - const bool is_metadata = IsMetaDataStreamDictionary(GetDict()); - CPDF_FlateEncoder encoder(this, !is_metadata); + const bool is_metadata = IsMetaDataStreamDictionary(GetDict().Get()); + CPDF_FlateEncoder encoder(pdfium::WrapRetain(this), !is_metadata); - std::vector<uint8_t> encrypted_data; + DataVector<uint8_t> encrypted_data; pdfium::span<const uint8_t> data = encoder.GetSpan(); - if (encryptor && !is_metadata) { encrypted_data = encryptor->Encrypt(data); data = encrypted_data; } - size_t size = data.size(); - if (static_cast<size_t>(encoder.GetDict()->GetIntegerFor("Length")) != size) { - encoder.CloneDict(); - encoder.GetClonedDict()->SetNewFor<CPDF_Number>("Length", - static_cast<int>(size)); - } - - if (!encoder.GetDict()->WriteTo(archive, encryptor)) + encoder.UpdateLength(data.size()); + if (!encoder.WriteDictTo(archive, encryptor)) return false; if (!archive->WriteString("stream\r\n")) return false; - if (size && !archive->WriteBlock(data.data(), size)) + if (!archive->WriteBlock(data)) return false; - if (!archive->WriteString("\r\nendstream")) - return false; + return archive->WriteString("\r\nendstream"); +} - return true; +size_t CPDF_Stream::GetRawSize() const { + if (IsFileBased()) { + return pdfium::base::checked_cast<size_t>( + absl::get<RetainPtr<IFX_SeekableReadStream>>(data_)->GetSize()); + } + if (IsMemoryBased()) + return absl::get<DataVector<uint8_t>>(data_).size(); + DCHECK(IsUninitialized()); + return 0; +} + +pdfium::span<const uint8_t> CPDF_Stream::GetInMemoryRawData() const { + DCHECK(IsMemoryBased()); + return absl::get<DataVector<uint8_t>>(data_); +} + +void CPDF_Stream::SetLengthInDict(int length) { + if (!dict_) + dict_ = pdfium::MakeRetain<CPDF_Dictionary>(); + dict_->SetNewFor<CPDF_Number>("Length", length); }
diff --git a/core/fpdfapi/parser/cpdf_stream.h b/core/fpdfapi/parser/cpdf_stream.h index d29f655..f1bb78b 100644 --- a/core/fpdfapi/parser/cpdf_stream.h +++ b/core/fpdfapi/parser/cpdf_stream.h
@@ -1,4 +1,4 @@ -// Copyright 2016 PDFium Authors. All rights reserved. +// Copyright 2016 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -7,80 +7,96 @@ #ifndef CORE_FPDFAPI_PARSER_CPDF_STREAM_H_ #define CORE_FPDFAPI_PARSER_CPDF_STREAM_H_ +#include <stdint.h> + #include <memory> #include <set> -#include <sstream> #include "core/fpdfapi/parser/cpdf_object.h" -#include "core/fxcrt/fx_memory_wrappers.h" -#include "core/fxcrt/fx_stream.h" +#include "core/fxcrt/data_vector.h" +#include "core/fxcrt/fx_string_wrappers.h" +#include "core/fxcrt/retain_ptr.h" +#include "third_party/abseil-cpp/absl/types/variant.h" + +class IFX_SeekableReadStream; class CPDF_Stream final : public CPDF_Object { public: - static const int kFileBufSize = 512; + static constexpr int kFileBufSize = 512; - template <typename T, typename... Args> - friend RetainPtr<T> pdfium::MakeRetain(Args&&... args); + CONSTRUCT_VIA_MAKE_RETAIN; // CPDF_Object: Type GetType() const override; RetainPtr<CPDF_Object> Clone() const override; - CPDF_Dictionary* GetDict() override; - const CPDF_Dictionary* GetDict() const override; WideString GetUnicodeText() const override; - bool IsStream() const override; - CPDF_Stream* AsStream() override; - const CPDF_Stream* AsStream() const override; + CPDF_Stream* AsMutableStream() override; bool WriteTo(IFX_ArchiveStream* archive, const CPDF_Encryptor* encryptor) const override; - uint32_t GetRawSize() const { return m_dwSize; } - // Will be null in case when stream is not memory based. - // Use CPDF_StreamAcc to data access in all cases. - uint8_t* GetInMemoryRawData() const { return m_pDataBuf.get(); } + size_t GetRawSize() const; + // Can only be called when stream is memory-based. + // This is meant to be used by CPDF_StreamAcc only. + // Other callers should use CPDF_StreamAcc to access data in all cases. + pdfium::span<const uint8_t> GetInMemoryRawData() const; - // Copies span into internally-owned buffer. + // Copies span or stream into internally-owned buffer. void SetData(pdfium::span<const uint8_t> pData); + void SetDataFromStringstream(fxcrt::ostringstream* stream); - void TakeData(std::unique_ptr<uint8_t, FxFreeDeleter> pData, uint32_t size); - - void SetDataFromStringstream(std::ostringstream* stream); + void TakeData(DataVector<uint8_t> data); // Set data and remove "Filter" and "DecodeParms" fields from stream - // dictionary. + // dictionary. Copies span or stream into internally-owned buffer. void SetDataAndRemoveFilter(pdfium::span<const uint8_t> pData); - void SetDataFromStringstreamAndRemoveFilter(std::ostringstream* stream); + void SetDataFromStringstreamAndRemoveFilter(fxcrt::ostringstream* stream); - void InitStream(pdfium::span<const uint8_t> pData, - RetainPtr<CPDF_Dictionary> pDict); - void InitStreamFromFile(const RetainPtr<IFX_SeekableReadStream>& pFile, + void InitStreamWithEmptyData(RetainPtr<CPDF_Dictionary> pDict); + void InitStreamFromFile(RetainPtr<IFX_SeekableReadStream> pFile, RetainPtr<CPDF_Dictionary> pDict); - bool ReadRawData(FX_FILESIZE offset, uint8_t* pBuf, uint32_t buf_size) const; + // Can only be called when a stream is not memory-based. + DataVector<uint8_t> ReadAllRawData() const; - bool IsMemoryBased() const { return m_bMemoryBased; } + bool IsUninitialized() const { + return absl::holds_alternative<absl::monostate>(data_); + } + bool IsFileBased() const { + return absl::holds_alternative<RetainPtr<IFX_SeekableReadStream>>(data_); + } + bool IsMemoryBased() const { + return absl::holds_alternative<DataVector<uint8_t>>(data_); + } bool HasFilter() const; private: + friend class CPDF_Dictionary; + + // Uninitialized. CPDF_Stream(); - CPDF_Stream(std::unique_ptr<uint8_t, FxFreeDeleter> pData, - uint32_t size, - RetainPtr<CPDF_Dictionary> pDict); + + // Initializes with empty data. + explicit CPDF_Stream(RetainPtr<CPDF_Dictionary> pDict); + + CPDF_Stream(DataVector<uint8_t> pData, RetainPtr<CPDF_Dictionary> pDict); ~CPDF_Stream() override; + const CPDF_Dictionary* GetDictInternal() const override; RetainPtr<CPDF_Object> CloneNonCyclic( bool bDirect, std::set<const CPDF_Object*>* pVisited) const override; - bool m_bMemoryBased = true; - uint32_t m_dwSize = 0; - RetainPtr<CPDF_Dictionary> m_pDict; - std::unique_ptr<uint8_t, FxFreeDeleter> m_pDataBuf; - RetainPtr<IFX_SeekableReadStream> m_pFile; + void SetLengthInDict(int length); + + absl::variant<absl::monostate, + RetainPtr<IFX_SeekableReadStream>, + DataVector<uint8_t>> + data_; + RetainPtr<CPDF_Dictionary> dict_; }; inline CPDF_Stream* ToStream(CPDF_Object* obj) { - return obj ? obj->AsStream() : nullptr; + return obj ? obj->AsMutableStream() : nullptr; } inline const CPDF_Stream* ToStream(const CPDF_Object* obj) { @@ -91,4 +107,8 @@ return RetainPtr<CPDF_Stream>(ToStream(obj.Get())); } +inline RetainPtr<const CPDF_Stream> ToStream(RetainPtr<const CPDF_Object> obj) { + return RetainPtr<const CPDF_Stream>(ToStream(obj.Get())); +} + #endif // CORE_FPDFAPI_PARSER_CPDF_STREAM_H_
diff --git a/core/fpdfapi/parser/cpdf_stream_acc.cpp b/core/fpdfapi/parser/cpdf_stream_acc.cpp index cd99751..4f42c6d 100644 --- a/core/fpdfapi/parser/cpdf_stream_acc.cpp +++ b/core/fpdfapi/parser/cpdf_stream_acc.cpp
@@ -1,4 +1,4 @@ -// Copyright 2016 PDFium Authors. All rights reserved. +// Copyright 2016 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -7,15 +7,16 @@ #include "core/fpdfapi/parser/cpdf_stream_acc.h" #include <utility> -#include <vector> #include "core/fdrm/fx_crypt.h" #include "core/fpdfapi/parser/cpdf_dictionary.h" #include "core/fpdfapi/parser/cpdf_stream.h" #include "core/fpdfapi/parser/fpdf_parser_decode.h" +#include "core/fxcrt/data_vector.h" +#include "third_party/base/check_op.h" -CPDF_StreamAcc::CPDF_StreamAcc(const CPDF_Stream* pStream) - : m_pStream(pStream) {} +CPDF_StreamAcc::CPDF_StreamAcc(RetainPtr<const CPDF_Stream> pStream) + : m_pStream(std::move(pStream)) {} CPDF_StreamAcc::~CPDF_StreamAcc() = default; @@ -23,8 +24,8 @@ uint32_t estimated_size, bool bImageAcc) { if (bRawAccess) { - ASSERT(!estimated_size); - ASSERT(!bImageAcc); + DCHECK(!estimated_size); + DCHECK(!bImageAcc); } if (!m_pStream) @@ -54,117 +55,117 @@ LoadAllData(true, 0, false); } -const CPDF_Dictionary* CPDF_StreamAcc::GetDict() const { - return m_pStream ? m_pStream->GetDict() : nullptr; +RetainPtr<const CPDF_Stream> CPDF_StreamAcc::GetStream() const { + return m_pStream; } -uint8_t* CPDF_StreamAcc::GetData() const { - if (m_pData.IsOwned()) - return m_pData.Get(); - return m_pStream ? m_pStream->GetInMemoryRawData() : nullptr; +int CPDF_StreamAcc::GetLength1ForTest() const { + return m_pStream->GetDict()->GetIntegerFor("Length1"); +} + +RetainPtr<const CPDF_Dictionary> CPDF_StreamAcc::GetImageParam() const { + return m_pImageParam; } uint32_t CPDF_StreamAcc::GetSize() const { - if (m_pData.IsOwned()) - return m_dwSize; - return (m_pStream && m_pStream->IsMemoryBased()) ? m_pStream->GetRawSize() - : 0; -} - -pdfium::span<uint8_t> CPDF_StreamAcc::GetSpan() { - return {GetData(), GetSize()}; + return GetSpan().size(); } pdfium::span<const uint8_t> CPDF_StreamAcc::GetSpan() const { - return {GetData(), GetSize()}; + if (is_owned()) + return absl::get<DataVector<uint8_t>>(m_Data); + if (m_pStream && m_pStream->IsMemoryBased()) + return m_pStream->GetInMemoryRawData(); + return {}; +} + +uint64_t CPDF_StreamAcc::KeyForCache() const { + return m_pStream ? m_pStream->KeyForCache() : 0; } ByteString CPDF_StreamAcc::ComputeDigest() const { uint8_t digest[20]; - CRYPT_SHA1Generate(GetData(), GetSize(), digest); + pdfium::span<const uint8_t> span = GetSpan(); + CRYPT_SHA1Generate(span.data(), span.size(), digest); return ByteString(digest, 20); } -std::unique_ptr<uint8_t, FxFreeDeleter> CPDF_StreamAcc::DetachData() { - if (m_pData.IsOwned()) { - std::unique_ptr<uint8_t, FxFreeDeleter> p = m_pData.ReleaseAndClear(); - m_dwSize = 0; - return p; - } - std::unique_ptr<uint8_t, FxFreeDeleter> p(FX_Alloc(uint8_t, m_dwSize)); - memcpy(p.get(), m_pData.Get(), m_dwSize); - return p; +DataVector<uint8_t> CPDF_StreamAcc::DetachData() { + if (is_owned()) + return std::move(absl::get<DataVector<uint8_t>>(m_Data)); + + auto span = absl::get<pdfium::span<const uint8_t>>(m_Data); + return DataVector<uint8_t>(span.begin(), span.end()); } void CPDF_StreamAcc::ProcessRawData() { + if (m_pStream->IsUninitialized()) + return; + uint32_t dwSrcSize = m_pStream->GetRawSize(); if (dwSrcSize == 0) return; if (m_pStream->IsMemoryBased()) { - m_pData = m_pStream->GetInMemoryRawData(); - m_dwSize = dwSrcSize; + m_Data = m_pStream->GetInMemoryRawData(); return; } - std::unique_ptr<uint8_t, FxFreeDeleter> pData = ReadRawStream(); - if (!pData) + DataVector<uint8_t> data = ReadRawStream(); + if (data.empty()) return; - m_pData = std::move(pData); - m_dwSize = dwSrcSize; + m_Data = std::move(data); } void CPDF_StreamAcc::ProcessFilteredData(uint32_t estimated_size, bool bImageAcc) { + if (m_pStream->IsUninitialized()) + return; + uint32_t dwSrcSize = m_pStream->GetRawSize(); if (dwSrcSize == 0) return; - MaybeOwned<uint8_t, FxFreeDeleter> pSrcData; + absl::variant<pdfium::span<const uint8_t>, DataVector<uint8_t>> src_data; + pdfium::span<const uint8_t> src_span; if (m_pStream->IsMemoryBased()) { - pSrcData = m_pStream->GetInMemoryRawData(); + src_span = m_pStream->GetInMemoryRawData(); + src_data = src_span; } else { - std::unique_ptr<uint8_t, FxFreeDeleter> pTempSrcData = ReadRawStream(); - if (!pTempSrcData) + DataVector<uint8_t> temp_src_data = ReadRawStream(); + if (temp_src_data.empty()) return; - pSrcData = std::move(pTempSrcData); + src_span = pdfium::make_span(temp_src_data); + src_data = std::move(temp_src_data); } std::unique_ptr<uint8_t, FxFreeDeleter> pDecodedData; uint32_t dwDecodedSize = 0; - Optional<std::vector<std::pair<ByteString, const CPDF_Object*>>> - decoder_array = GetDecoderArray(m_pStream->GetDict()); - if (!decoder_array.has_value() || - !PDF_DataDecode({pSrcData.Get(), dwSrcSize}, estimated_size, bImageAcc, + absl::optional<DecoderArray> decoder_array = + GetDecoderArray(m_pStream->GetDict()); + if (!decoder_array.has_value() || decoder_array.value().empty() || + !PDF_DataDecode(src_span, estimated_size, bImageAcc, decoder_array.value(), &pDecodedData, &dwDecodedSize, &m_ImageDecoder, &m_pImageParam)) { - m_pData = std::move(pSrcData); - m_dwSize = dwSrcSize; + m_Data = std::move(src_data); return; } if (pDecodedData) { - ASSERT(pDecodedData.get() != pSrcData.Get()); - m_pData = std::move(pDecodedData); - m_dwSize = dwDecodedSize; + DCHECK_NE(pDecodedData.get(), src_span.data()); + // TODO(crbug.com/pdfium/1872): Avoid copying. + m_Data = DataVector<uint8_t>(pDecodedData.get(), + pDecodedData.get() + dwDecodedSize); } else { - m_pData = std::move(pSrcData); - m_dwSize = dwSrcSize; + m_Data = std::move(src_data); } } -std::unique_ptr<uint8_t, FxFreeDeleter> CPDF_StreamAcc::ReadRawStream() const { - ASSERT(m_pStream); - ASSERT(!m_pStream->IsMemoryBased()); - - uint32_t dwSrcSize = m_pStream->GetRawSize(); - ASSERT(dwSrcSize); - std::unique_ptr<uint8_t, FxFreeDeleter> pSrcData( - FX_Alloc(uint8_t, dwSrcSize)); - if (!m_pStream->ReadRawData(0, pSrcData.get(), dwSrcSize)) - return nullptr; - return pSrcData; +DataVector<uint8_t> CPDF_StreamAcc::ReadRawStream() const { + DCHECK(m_pStream); + DCHECK(m_pStream->IsFileBased()); + return m_pStream->ReadAllRawData(); }
diff --git a/core/fpdfapi/parser/cpdf_stream_acc.h b/core/fpdfapi/parser/cpdf_stream_acc.h index 046fe5d..1f0e726 100644 --- a/core/fpdfapi/parser/cpdf_stream_acc.h +++ b/core/fpdfapi/parser/cpdf_stream_acc.h
@@ -1,4 +1,4 @@ -// Copyright 2016 PDFium Authors. All rights reserved. +// Copyright 2016 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -7,13 +7,14 @@ #ifndef CORE_FPDFAPI_PARSER_CPDF_STREAM_ACC_H_ #define CORE_FPDFAPI_PARSER_CPDF_STREAM_ACC_H_ +#include <stdint.h> + #include <memory> -#include "core/fxcrt/fx_memory_wrappers.h" -#include "core/fxcrt/fx_string.h" -#include "core/fxcrt/fx_system.h" -#include "core/fxcrt/maybe_owned.h" +#include "core/fxcrt/bytestring.h" +#include "core/fxcrt/data_vector.h" #include "core/fxcrt/retain_ptr.h" +#include "third_party/abseil-cpp/absl/types/variant.h" #include "third_party/base/span.h" class CPDF_Dictionary; @@ -21,8 +22,7 @@ class CPDF_StreamAcc final : public Retainable { public: - template <typename T, typename... Args> - friend RetainPtr<T> pdfium::MakeRetain(Args&&... args); + CONSTRUCT_VIA_MAKE_RETAIN; CPDF_StreamAcc(const CPDF_StreamAcc&) = delete; CPDF_StreamAcc& operator=(const CPDF_StreamAcc&) = delete; @@ -32,34 +32,38 @@ void LoadAllDataImageAcc(uint32_t estimated_size); void LoadAllDataRaw(); - const CPDF_Stream* GetStream() const { return m_pStream.Get(); } - const CPDF_Dictionary* GetDict() const; + RetainPtr<const CPDF_Stream> GetStream() const; + RetainPtr<const CPDF_Dictionary> GetImageParam() const; - uint8_t* GetData() const; uint32_t GetSize() const; - pdfium::span<uint8_t> GetSpan(); pdfium::span<const uint8_t> GetSpan() const; + uint64_t KeyForCache() const; ByteString ComputeDigest() const; ByteString GetImageDecoder() const { return m_ImageDecoder; } - const CPDF_Dictionary* GetImageParam() const { return m_pImageParam.Get(); } - std::unique_ptr<uint8_t, FxFreeDeleter> DetachData(); + DataVector<uint8_t> DetachData(); + + int GetLength1ForTest() const; private: - explicit CPDF_StreamAcc(const CPDF_Stream* pStream); + explicit CPDF_StreamAcc(RetainPtr<const CPDF_Stream> pStream); ~CPDF_StreamAcc() override; void LoadAllData(bool bRawAccess, uint32_t estimated_size, bool bImageAcc); void ProcessRawData(); void ProcessFilteredData(uint32_t estimated_size, bool bImageAcc); - // Reads the raw data from |m_pStream|, or return nullptr on failure. - std::unique_ptr<uint8_t, FxFreeDeleter> ReadRawStream() const; + // Returns the raw data from `m_pStream`, or no data on failure. + DataVector<uint8_t> ReadRawStream() const; - MaybeOwned<uint8_t, FxFreeDeleter> m_pData; - uint32_t m_dwSize = 0; + bool is_owned() const { + return absl::holds_alternative<DataVector<uint8_t>>(m_Data); + } + ByteString m_ImageDecoder; RetainPtr<const CPDF_Dictionary> m_pImageParam; + // Needs to outlive `m_Data` when the data is not owned. RetainPtr<const CPDF_Stream> const m_pStream; + absl::variant<pdfium::span<const uint8_t>, DataVector<uint8_t>> m_Data; }; #endif // CORE_FPDFAPI_PARSER_CPDF_STREAM_ACC_H_
diff --git a/core/fpdfapi/parser/cpdf_stream_acc_unittest.cpp b/core/fpdfapi/parser/cpdf_stream_acc_unittest.cpp index 72ba93d..c22e655 100644 --- a/core/fpdfapi/parser/cpdf_stream_acc_unittest.cpp +++ b/core/fpdfapi/parser/cpdf_stream_acc_unittest.cpp
@@ -1,22 +1,35 @@ -// Copyright 2018 PDFium Authors. All rights reserved. +// Copyright 2018 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "core/fpdfapi/parser/cpdf_stream_acc.h" +#include <utility> + #include "core/fpdfapi/parser/cpdf_dictionary.h" #include "core/fpdfapi/parser/cpdf_stream.h" #include "core/fxcrt/fx_stream.h" #include "testing/gtest/include/gtest/gtest.h" #include "testing/invalid_seekable_read_stream.h" -TEST(CPDF_StreamAccTest, ReadRawDataFailed) { +TEST(StreamAccTest, ReadRawDataFailed) { auto stream = pdfium::MakeRetain<CPDF_Stream>(); stream->InitStreamFromFile( pdfium::MakeRetain<InvalidSeekableReadStream>(1024), pdfium::MakeRetain<CPDF_Dictionary>()); - auto stream_acc = pdfium::MakeRetain<CPDF_StreamAcc>(stream.Get()); + auto stream_acc = pdfium::MakeRetain<CPDF_StreamAcc>(std::move(stream)); stream_acc->LoadAllDataRaw(); - EXPECT_EQ(0u, stream_acc->GetSize()); - EXPECT_FALSE(stream_acc->GetData()); + EXPECT_TRUE(stream_acc->GetSpan().empty()); +} + +// Regression test for crbug.com/1361849. Should not trigger +// ProbeForLowSeverityLifetimeIssue() failure. +TEST(StreamAccTest, DataStreamLifeTime) { + constexpr uint8_t kData[] = {'a', 'b', 'c'}; + auto stream = pdfium::MakeRetain<CPDF_Stream>(); + stream->SetData(kData); + auto stream_acc = pdfium::MakeRetain<CPDF_StreamAcc>(stream); + stream_acc->LoadAllDataRaw(); + stream.Reset(); + EXPECT_EQ(pdfium::make_span(kData), stream_acc->GetSpan()); }
diff --git a/core/fpdfapi/parser/cpdf_string.cpp b/core/fpdfapi/parser/cpdf_string.cpp index 7058169..7716926 100644 --- a/core/fpdfapi/parser/cpdf_string.cpp +++ b/core/fpdfapi/parser/cpdf_string.cpp
@@ -1,4 +1,4 @@ -// Copyright 2016 PDFium Authors. All rights reserved. +// Copyright 2016 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -6,13 +6,14 @@ #include "core/fpdfapi/parser/cpdf_string.h" +#include <stdint.h> + #include <utility> -#include <vector> #include "core/fpdfapi/parser/cpdf_encryptor.h" #include "core/fpdfapi/parser/fpdf_parser_decode.h" +#include "core/fxcrt/data_vector.h" #include "core/fxcrt/fx_stream.h" -#include "third_party/base/ptr_util.h" CPDF_String::CPDF_String() = default; @@ -24,7 +25,7 @@ m_String = pPool->Intern(m_String); } -CPDF_String::CPDF_String(WeakPtr<ByteStringPool> pPool, const WideString& str) +CPDF_String::CPDF_String(WeakPtr<ByteStringPool> pPool, WideStringView str) : m_String(PDF_EncodeText(str)) { if (pPool) m_String = pPool->Intern(m_String); @@ -51,15 +52,7 @@ m_String = str; } -bool CPDF_String::IsString() const { - return true; -} - -CPDF_String* CPDF_String::AsString() { - return this; -} - -const CPDF_String* CPDF_String::AsString() const { +CPDF_String* CPDF_String::AsMutableString() { return this; } @@ -69,13 +62,19 @@ bool CPDF_String::WriteTo(IFX_ArchiveStream* archive, const CPDF_Encryptor* encryptor) const { - std::vector<uint8_t> encrypted_data; + DataVector<uint8_t> encrypted_data; pdfium::span<const uint8_t> data = m_String.raw_span(); if (encryptor) { encrypted_data = encryptor->Encrypt(data); data = encrypted_data; } - const ByteString content = - PDF_EncodeString(ByteString(data.data(), data.size()), IsHex()); + ByteStringView raw(data.data(), data.size()); + ByteString content = + m_bHex ? PDF_HexEncodeString(raw) : PDF_EncodeString(raw); return archive->WriteString(content.AsStringView()); } + +ByteString CPDF_String::EncodeString() const { + return m_bHex ? PDF_HexEncodeString(m_String.AsStringView()) + : PDF_EncodeString(m_String.AsStringView()); +}
diff --git a/core/fpdfapi/parser/cpdf_string.h b/core/fpdfapi/parser/cpdf_string.h index 8efc71b..5ae6277 100644 --- a/core/fpdfapi/parser/cpdf_string.h +++ b/core/fpdfapi/parser/cpdf_string.h
@@ -1,4 +1,4 @@ -// Copyright 2016 PDFium Authors. All rights reserved. +// Copyright 2016 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -7,18 +7,15 @@ #ifndef CORE_FPDFAPI_PARSER_CPDF_STRING_H_ #define CORE_FPDFAPI_PARSER_CPDF_STRING_H_ -#include <memory> - #include "core/fpdfapi/parser/cpdf_object.h" #include "core/fxcrt/fx_string.h" -#include "core/fxcrt/fx_system.h" +#include "core/fxcrt/retain_ptr.h" #include "core/fxcrt/string_pool_template.h" #include "core/fxcrt/weak_ptr.h" class CPDF_String final : public CPDF_Object { public: - template <typename T, typename... Args> - friend RetainPtr<T> pdfium::MakeRetain(Args&&... args); + CONSTRUCT_VIA_MAKE_RETAIN; // CPDF_Object: Type GetType() const override; @@ -26,18 +23,17 @@ ByteString GetString() const override; WideString GetUnicodeText() const override; void SetString(const ByteString& str) override; - bool IsString() const override; - CPDF_String* AsString() override; - const CPDF_String* AsString() const override; + CPDF_String* AsMutableString() override; bool WriteTo(IFX_ArchiveStream* archive, const CPDF_Encryptor* encryptor) const override; bool IsHex() const { return m_bHex; } + ByteString EncodeString() const; private: CPDF_String(); CPDF_String(WeakPtr<ByteStringPool> pPool, const ByteString& str, bool bHex); - CPDF_String(WeakPtr<ByteStringPool> pPool, const WideString& str); + CPDF_String(WeakPtr<ByteStringPool> pPool, WideStringView str); ~CPDF_String() override; ByteString m_String; @@ -45,11 +41,15 @@ }; inline CPDF_String* ToString(CPDF_Object* obj) { - return obj ? obj->AsString() : nullptr; + return obj ? obj->AsMutableString() : nullptr; } inline const CPDF_String* ToString(const CPDF_Object* obj) { return obj ? obj->AsString() : nullptr; } +inline RetainPtr<const CPDF_String> ToString(RetainPtr<const CPDF_Object> obj) { + return RetainPtr<const CPDF_String>(ToString(obj.Get())); +} + #endif // CORE_FPDFAPI_PARSER_CPDF_STRING_H_
diff --git a/core/fpdfapi/parser/cpdf_syntax_parser.cpp b/core/fpdfapi/parser/cpdf_syntax_parser.cpp index 0a55c27..0a85e8e 100644 --- a/core/fpdfapi/parser/cpdf_syntax_parser.cpp +++ b/core/fpdfapi/parser/cpdf_syntax_parser.cpp
@@ -1,4 +1,4 @@ -// Copyright 2016 PDFium Authors. All rights reserved. +// Copyright 2016 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -6,10 +6,10 @@ #include "core/fpdfapi/parser/cpdf_syntax_parser.h" +#include <ctype.h> + #include <algorithm> -#include <sstream> #include <utility> -#include <vector> #include "core/fpdfapi/parser/cpdf_array.h" #include "core/fpdfapi/parser/cpdf_boolean.h" @@ -24,39 +24,46 @@ #include "core/fpdfapi/parser/cpdf_string.h" #include "core/fpdfapi/parser/fpdf_parser_utility.h" #include "core/fxcrt/autorestorer.h" -#include "core/fxcrt/cfx_binarybuf.h" +#include "core/fxcrt/cfx_read_only_vector_stream.h" +#include "core/fxcrt/fixed_uninit_data_vector.h" #include "core/fxcrt/fx_extension.h" #include "core/fxcrt/fx_safe_types.h" +#include "third_party/base/check.h" +#include "third_party/base/check_op.h" #include "third_party/base/numerics/safe_math.h" -#include "third_party/base/ptr_util.h" namespace { -enum class ReadStatus { Normal, Backslash, Octal, FinishOctal, CarriageReturn }; +enum class ReadStatus { + kNormal, + kBackslash, + kOctal, + kFinishOctal, + kCarriageReturn +}; class ReadableSubStream final : public IFX_SeekableReadStream { public: - ReadableSubStream(const RetainPtr<IFX_SeekableReadStream>& pFileRead, + ReadableSubStream(RetainPtr<IFX_SeekableReadStream> pFileRead, FX_FILESIZE part_offset, FX_FILESIZE part_size) - : m_pFileRead(pFileRead), + : m_pFileRead(std::move(pFileRead)), m_PartOffset(part_offset), m_PartSize(part_size) {} ~ReadableSubStream() override = default; // IFX_SeekableReadStream overrides: - bool ReadBlockAtOffset(void* buffer, - FX_FILESIZE offset, - size_t size) override { + bool ReadBlockAtOffset(pdfium::span<uint8_t> buffer, + FX_FILESIZE offset) override { FX_SAFE_FILESIZE safe_end = offset; - safe_end += size; + safe_end += buffer.size(); // Check that requested range is valid, to prevent calling of ReadBlock // of original m_pFileRead with incorrect params. if (!safe_end.IsValid() || safe_end.ValueOrDie() > m_PartSize) return false; - return m_pFileRead->ReadBlockAtOffset(buffer, m_PartOffset + offset, size); + return m_pFileRead->ReadBlockAtOffset(buffer, m_PartOffset + offset); } FX_FILESIZE GetSize() override { return m_PartSize; } @@ -74,26 +81,26 @@ // static std::unique_ptr<CPDF_SyntaxParser> CPDF_SyntaxParser::CreateForTesting( - const RetainPtr<IFX_SeekableReadStream>& pFileAccess, + RetainPtr<IFX_SeekableReadStream> pFileAccess, FX_FILESIZE HeaderOffset) { - return pdfium::MakeUnique<CPDF_SyntaxParser>( - pdfium::MakeRetain<CPDF_ReadValidator>(pFileAccess, nullptr), + return std::make_unique<CPDF_SyntaxParser>( + pdfium::MakeRetain<CPDF_ReadValidator>(std::move(pFileAccess), nullptr), HeaderOffset); } CPDF_SyntaxParser::CPDF_SyntaxParser( - const RetainPtr<IFX_SeekableReadStream>& pFileAccess) + RetainPtr<IFX_SeekableReadStream> pFileAccess) : CPDF_SyntaxParser( - pdfium::MakeRetain<CPDF_ReadValidator>(pFileAccess, nullptr), + pdfium::MakeRetain<CPDF_ReadValidator>(std::move(pFileAccess), + nullptr), 0) {} -CPDF_SyntaxParser::CPDF_SyntaxParser( - const RetainPtr<CPDF_ReadValidator>& validator, - FX_FILESIZE HeaderOffset) - : m_pFileAccess(validator), +CPDF_SyntaxParser::CPDF_SyntaxParser(RetainPtr<CPDF_ReadValidator> validator, + FX_FILESIZE HeaderOffset) + : m_pFileAccess(std::move(validator)), m_HeaderOffset(HeaderOffset), m_FileLen(m_pFileAccess->GetSize()) { - ASSERT(m_HeaderOffset <= m_FileLen); + DCHECK(m_HeaderOffset <= m_FileLen); } CPDF_SyntaxParser::~CPDF_SyntaxParser() = default; @@ -114,8 +121,7 @@ read_size = m_FileLen - read_pos; m_pFileBuf.resize(read_size); - if (!m_pFileAccess->ReadBlockAtOffset(m_pFileBuf.data(), read_pos, - read_size)) { + if (!m_pFileAccess->ReadBlockAtOffset(m_pFileBuf, read_pos)) { m_pFileBuf.clear(); return false; } @@ -157,36 +163,34 @@ return true; } -bool CPDF_SyntaxParser::ReadBlock(uint8_t* pBuf, uint32_t size) { - if (!m_pFileAccess->ReadBlockAtOffset(pBuf, m_Pos + m_HeaderOffset, size)) +bool CPDF_SyntaxParser::ReadBlock(pdfium::span<uint8_t> buffer) { + if (!m_pFileAccess->ReadBlockAtOffset(buffer, m_Pos + m_HeaderOffset)) return false; - m_Pos += size; + m_Pos += buffer.size(); return true; } -void CPDF_SyntaxParser::GetNextWordInternal(bool* bIsNumber) { +CPDF_SyntaxParser::WordType CPDF_SyntaxParser::GetNextWordInternal() { m_WordSize = 0; - if (bIsNumber) - *bIsNumber = true; + WordType word_type = WordType::kNumber; ToNextWord(); uint8_t ch; if (!GetNextChar(ch)) - return; + return word_type; if (PDFCharIsDelimiter(ch)) { - if (bIsNumber) - *bIsNumber = false; + word_type = WordType::kWord; m_WordBuffer[m_WordSize++] = ch; if (ch == '/') { - while (1) { + while (true) { if (!GetNextChar(ch)) - return; + return word_type; if (!PDFCharIsOther(ch) && !PDFCharIsNumeric(ch)) { m_Pos--; - return; + return word_type; } if (m_WordSize < sizeof(m_WordBuffer) - 1) @@ -194,7 +198,7 @@ } } else if (ch == '<') { if (!GetNextChar(ch)) - return; + return word_type; if (ch == '<') m_WordBuffer[m_WordSize++] = ch; @@ -202,33 +206,32 @@ m_Pos--; } else if (ch == '>') { if (!GetNextChar(ch)) - return; + return word_type; if (ch == '>') m_WordBuffer[m_WordSize++] = ch; else m_Pos--; } - return; + return word_type; } - while (1) { + while (true) { if (m_WordSize < sizeof(m_WordBuffer) - 1) m_WordBuffer[m_WordSize++] = ch; - if (!PDFCharIsNumeric(ch)) { - if (bIsNumber) - *bIsNumber = false; - } + if (!PDFCharIsNumeric(ch)) + word_type = WordType::kWord; if (!GetNextChar(ch)) - return; + return word_type; if (PDFCharIsDelimiter(ch) || PDFCharIsWhitespace(ch)) { m_Pos--; break; } } + return word_type; } ByteString CPDF_SyntaxParser::ReadString() { @@ -236,13 +239,13 @@ if (!GetNextChar(ch)) return ByteString(); - std::ostringstream buf; + ByteString buf; int32_t parlevel = 0; - ReadStatus status = ReadStatus::Normal; + ReadStatus status = ReadStatus::kNormal; int32_t iEscCode = 0; - while (1) { + while (true) { switch (status) { - case ReadStatus::Normal: + case ReadStatus::kNormal: if (ch == ')') { if (parlevel == 0) return ByteString(buf); @@ -251,60 +254,59 @@ parlevel++; } if (ch == '\\') - status = ReadStatus::Backslash; + status = ReadStatus::kBackslash; else - buf << static_cast<char>(ch); + buf += static_cast<char>(ch); break; - case ReadStatus::Backslash: + case ReadStatus::kBackslash: if (FXSYS_IsOctalDigit(ch)) { iEscCode = FXSYS_DecimalCharToInt(static_cast<wchar_t>(ch)); - status = ReadStatus::Octal; + status = ReadStatus::kOctal; break; } - if (ch == '\r') { - status = ReadStatus::CarriageReturn; + status = ReadStatus::kCarriageReturn; break; } if (ch == 'n') { - buf << '\n'; + buf += '\n'; } else if (ch == 'r') { - buf << '\r'; + buf += '\r'; } else if (ch == 't') { - buf << '\t'; + buf += '\t'; } else if (ch == 'b') { - buf << '\b'; + buf += '\b'; } else if (ch == 'f') { - buf << '\f'; + buf += '\f'; } else if (ch != '\n') { - buf << static_cast<char>(ch); + buf += static_cast<char>(ch); } - status = ReadStatus::Normal; + status = ReadStatus::kNormal; break; - case ReadStatus::Octal: + case ReadStatus::kOctal: if (FXSYS_IsOctalDigit(ch)) { iEscCode = iEscCode * 8 + FXSYS_DecimalCharToInt(static_cast<wchar_t>(ch)); - status = ReadStatus::FinishOctal; + status = ReadStatus::kFinishOctal; } else { - buf << static_cast<char>(iEscCode); - status = ReadStatus::Normal; + buf += static_cast<char>(iEscCode); + status = ReadStatus::kNormal; continue; } break; - case ReadStatus::FinishOctal: - status = ReadStatus::Normal; + case ReadStatus::kFinishOctal: + status = ReadStatus::kNormal; if (FXSYS_IsOctalDigit(ch)) { iEscCode = iEscCode * 8 + FXSYS_DecimalCharToInt(static_cast<wchar_t>(ch)); - buf << static_cast<char>(iEscCode); + buf += static_cast<char>(iEscCode); } else { - buf << static_cast<char>(iEscCode); + buf += static_cast<char>(iEscCode); continue; } break; - case ReadStatus::CarriageReturn: - status = ReadStatus::Normal; + case ReadStatus::kCarriageReturn: + status = ReadStatus::kNormal; if (ch != '\n') continue; break; @@ -315,7 +317,7 @@ } GetNextChar(ch); - return ByteString(buf); + return buf; } ByteString CPDF_SyntaxParser::ReadHexString() { @@ -323,20 +325,20 @@ if (!GetNextChar(ch)) return ByteString(); - std::ostringstream buf; + ByteString buf; bool bFirst = true; uint8_t code = 0; - while (1) { + while (true) { if (ch == '>') break; - if (std::isxdigit(ch)) { + if (isxdigit(ch)) { int val = FXSYS_HexCharToInt(ch); if (bFirst) { code = val * 16; } else { code += val; - buf << static_cast<char>(code); + buf += static_cast<char>(code); } bFirst = !bFirst; } @@ -345,9 +347,9 @@ break; } if (!bFirst) - buf << static_cast<char>(code); + buf += static_cast<char>(code); - return ByteString(buf); + return buf; } void CPDF_SyntaxParser::ToNextLine() { @@ -366,11 +368,16 @@ } void CPDF_SyntaxParser::ToNextWord() { + if (m_TrailerEnds) { + RecordingToNextWord(); + return; + } + uint8_t ch; if (!GetNextChar(ch)) return; - while (1) { + while (true) { while (PDFCharIsWhitespace(ch)) { if (!GetNextChar(ch)) return; @@ -379,7 +386,7 @@ if (ch != '%') break; - while (1) { + while (true) { if (!GetNextChar(ch)) return; if (PDFCharIsLineEnding(ch)) @@ -389,31 +396,97 @@ m_Pos--; } -ByteString CPDF_SyntaxParser::GetNextWord(bool* bIsNumber) { - const CPDF_ReadValidator::Session read_session(GetValidator()); - GetNextWordInternal(bIsNumber); - ByteString ret; - if (!GetValidator()->has_read_problems()) - ret = ByteString(m_WordBuffer, m_WordSize); - return ret; +// A state machine which goes % -> E -> O -> F -> line ending. +enum class EofState { + kInitial = 0, + kNonPercent, + kPercent, + kE, + kO, + kF, + kInvalid, +}; + +void CPDF_SyntaxParser::RecordingToNextWord() { + DCHECK(m_TrailerEnds); + + EofState eof_state = EofState::kInitial; + // Find the first character which is neither whitespace, nor part of a + // comment. + while (true) { + uint8_t ch; + if (!GetNextChar(ch)) + return; + switch (eof_state) { + case EofState::kInitial: + if (!PDFCharIsWhitespace(ch)) + eof_state = ch == '%' ? EofState::kPercent : EofState::kNonPercent; + break; + case EofState::kNonPercent: + break; + case EofState::kPercent: + if (ch == 'E') + eof_state = EofState::kE; + else if (ch != '%') + eof_state = EofState::kInvalid; + break; + case EofState::kE: + eof_state = ch == 'O' ? EofState::kO : EofState::kInvalid; + break; + case EofState::kO: + eof_state = ch == 'F' ? EofState::kF : EofState::kInvalid; + break; + case EofState::kF: + if (ch == '\r') { + // See if \r has to be combined with a \n that follows it + // immediately. + if (GetNextChar(ch) && ch != '\n') { + ch = '\r'; + m_Pos--; + } + } + // If we now have a \r, that's not followed by a \n, so both are OK. + if (ch == '\r' || ch == '\n') + m_TrailerEnds->push_back(m_Pos); + eof_state = EofState::kInvalid; + break; + case EofState::kInvalid: + break; + } + if (PDFCharIsLineEnding(ch)) + eof_state = EofState::kInitial; + if (eof_state == EofState::kNonPercent) + break; + } + m_Pos--; } -ByteString CPDF_SyntaxParser::PeekNextWord(bool* bIsNumber) { +CPDF_SyntaxParser::WordResult CPDF_SyntaxParser::GetNextWord() { + CPDF_ReadValidator::ScopedSession read_session(GetValidator()); + WordType word_type = GetNextWordInternal(); + ByteString word; + if (!GetValidator()->has_read_problems()) + word = ByteString(m_WordBuffer, m_WordSize); + return {word, word_type == WordType::kNumber}; +} + +ByteString CPDF_SyntaxParser::PeekNextWord() { AutoRestorer<FX_FILESIZE> save_pos(&m_Pos); - return GetNextWord(bIsNumber); + return GetNextWord().word; } ByteString CPDF_SyntaxParser::GetKeyword() { - return GetNextWord(nullptr); + return GetNextWord().word; } void CPDF_SyntaxParser::SetPos(FX_FILESIZE pos) { + DCHECK_GE(pos, 0); m_Pos = std::min(pos, m_FileLen); } RetainPtr<CPDF_Object> CPDF_SyntaxParser::GetObjectBody( CPDF_IndirectObjectHolder* pObjList) { - const CPDF_ReadValidator::Session read_session(GetValidator()); + CPDF_ReadValidator::ScopedSession read_session(GetValidator()); auto result = GetObjectBodyInternal(pObjList, ParseType::kLoose); if (GetValidator()->has_read_problems()) return nullptr; @@ -428,19 +501,19 @@ return nullptr; FX_FILESIZE SavedObjPos = m_Pos; - bool bIsNumber; - ByteString word = GetNextWord(&bIsNumber); + WordResult word_result = GetNextWord(); + const ByteString& word = word_result.word; if (word.IsEmpty()) return nullptr; - if (bIsNumber) { + if (word_result.is_number) { AutoRestorer<FX_FILESIZE> pos_restorer(&m_Pos); - ByteString nextword = GetNextWord(&bIsNumber); - if (!bIsNumber) + WordResult nextword = GetNextWord(); + if (!nextword.is_number) return pdfium::MakeRetain<CPDF_Number>(word.AsStringView()); - ByteString nextword2 = GetNextWord(nullptr); - if (nextword2 != "R") + WordResult nextword2 = GetNextWord(); + if (nextword2.word != "R") return pdfium::MakeRetain<CPDF_Number>(word.AsStringView()); pos_restorer.AbandonRestoration(); @@ -469,7 +542,7 @@ auto pArray = pdfium::MakeRetain<CPDF_Array>(); while (RetainPtr<CPDF_Object> pObj = GetObjectBodyInternal(pObjList, ParseType::kLoose)) { - pArray->Add(std::move(pObj)); + pArray->Append(std::move(pObj)); } return (parse_type == ParseType::kLoose || m_WordBuffer[0] == ']') ? std::move(pArray) @@ -483,8 +556,9 @@ if (word == "<<") { RetainPtr<CPDF_Dictionary> pDict = pdfium::MakeRetain<CPDF_Dictionary>(m_pPool); - while (1) { - ByteString inner_word = GetNextWord(nullptr); + while (true) { + WordResult inner_word_result = GetNextWord(); + const ByteString& inner_word = inner_word_result.word; if (inner_word.IsEmpty()) return nullptr; @@ -513,14 +587,14 @@ return nullptr; } - if (!key.IsEmpty()) { - ByteString keyNoSlash(key.raw_str() + 1, key.GetLength() - 1); - pDict->SetFor(keyNoSlash, std::move(pObj)); + // `key` has to be "/X" at the minimum. + if (key.GetLength() > 1) { + pDict->SetFor(key.Substr(1), std::move(pObj)); } } AutoRestorer<FX_FILESIZE> pos_restorer(&m_Pos); - if (GetNextWord(nullptr) != "stream") + if (GetNextWord().word != "stream") return pDict; pos_restorer.AbandonRestoration(); return ReadStream(std::move(pDict)); @@ -534,22 +608,23 @@ RetainPtr<CPDF_Object> CPDF_SyntaxParser::GetIndirectObject( CPDF_IndirectObjectHolder* pObjList, ParseType parse_type) { - const CPDF_ReadValidator::Session read_session(GetValidator()); + CPDF_ReadValidator::ScopedSession read_session(GetValidator()); const FX_FILESIZE saved_pos = GetPos(); - bool is_number = false; - ByteString word = GetNextWord(&is_number); - if (!is_number || word.IsEmpty()) { - SetPos(saved_pos); - return nullptr; - } - const uint32_t parser_objnum = FXSYS_atoui(word.c_str()); - word = GetNextWord(&is_number); - if (!is_number || word.IsEmpty()) { + WordResult objnum_word_result = GetNextWord(); + if (!objnum_word_result.is_number || objnum_word_result.word.IsEmpty()) { SetPos(saved_pos); return nullptr; } - const uint32_t parser_gennum = FXSYS_atoui(word.c_str()); + const uint32_t parser_objnum = FXSYS_atoui(objnum_word_result.word.c_str()); + + WordResult gennum_word_result = GetNextWord(); + const ByteString& gennum_word = gennum_word_result.word; + if (!gennum_word_result.is_number || gennum_word.IsEmpty()) { + SetPos(saved_pos); + return nullptr; + } + const uint32_t parser_gennum = FXSYS_atoui(gennum_word.c_str()); if (GetKeyword() != "obj") { SetPos(saved_pos); @@ -633,7 +708,8 @@ RetainPtr<CPDF_Stream> CPDF_SyntaxParser::ReadStream( RetainPtr<CPDF_Dictionary> pDict) { - const CPDF_Number* pLenObj = ToNumber(pDict->GetDirectObjectFor("Length")); + RetainPtr<const CPDF_Number> pLenObj = + ToNumber(pDict->GetDirectObjectFor("Length")); FX_FILESIZE len = pLenObj ? pLenObj->GetInteger() : -1; // Locate the start of stream. @@ -647,7 +723,7 @@ len = -1; } - RetainPtr<IFX_SeekableReadStream> data; + RetainPtr<IFX_SeekableReadStream> substream; if (len > 0) { // Check data availability first to allow the Validator to request data // smoothly, without jumps. @@ -656,7 +732,7 @@ return nullptr; } - data = pdfium::MakeRetain<ReadableSubStream>( + substream = pdfium::MakeRetain<ReadableSubStream>( GetValidator(), m_HeaderOffset + GetPos(), len); SetPos(GetPos() + len); } @@ -667,10 +743,10 @@ // Note, we allow zero length streams as we need to pass them through when we // are importing pages into a new document. if (len >= 0) { - const CPDF_ReadValidator::Session read_session(GetValidator()); + CPDF_ReadValidator::ScopedSession read_session(GetValidator()); m_Pos += ReadEOLMarkers(GetPos()); memset(m_WordBuffer, 0, kEndStreamStr.GetLength() + 1); - GetNextWordInternal(nullptr); + GetNextWordInternal(); if (GetValidator()->has_read_problems()) return nullptr; @@ -679,7 +755,7 @@ // specified length, it signals the end of stream. if (memcmp(m_WordBuffer, kEndStreamStr.raw_str(), kEndStreamStr.GetLength()) != 0) { - data.Reset(); + substream.Reset(); len = -1; SetPos(streamStartPos); } @@ -693,7 +769,7 @@ return nullptr; len = streamEndPos - streamStartPos; - ASSERT(len >= 0); + DCHECK_GE(len, 0); if (len > 0) { SetPos(streamStartPos); // Check data availability first to allow the Validator to request data @@ -703,22 +779,41 @@ return nullptr; } - data = pdfium::MakeRetain<ReadableSubStream>( + substream = pdfium::MakeRetain<ReadableSubStream>( GetValidator(), m_HeaderOffset + GetPos(), len); SetPos(GetPos() + len); } } - auto pStream = pdfium::MakeRetain<CPDF_Stream>(); - if (data) { - pStream->InitStreamFromFile(data, std::move(pDict)); + RetainPtr<CPDF_Stream> pStream; + if (substream) { + // It is unclear from CPDF_SyntaxParser's perspective what object + // `substream` is ultimately holding references to. To avoid unexpectedly + // changing object lifetimes by handing `substream` to `pStream`, make a + // copy of the data here. + FixedUninitDataVector<uint8_t> data(substream->GetSize()); + bool did_read = substream->ReadBlockAtOffset(data.writable_span(), 0); + CHECK(did_read); + auto data_as_stream = + pdfium::MakeRetain<CFX_ReadOnlyVectorStream>(std::move(data)); + + pStream = pdfium::MakeRetain<CPDF_Stream>(); + pStream->InitStreamFromFile(std::move(data_as_stream), std::move(pDict)); } else { DCHECK(!len); - pStream->InitStream({}, std::move(pDict)); // Empty stream + pStream = pdfium::MakeRetain<CPDF_Stream>(std::move(pDict)); } const FX_FILESIZE end_stream_offset = GetPos(); memset(m_WordBuffer, 0, kEndObjStr.GetLength() + 1); - GetNextWordInternal(nullptr); + GetNextWordInternal(); + + // Allow whitespace after endstream and before a newline. + unsigned char ch = 0; + while (GetNextChar(ch)) { + if (!PDFCharIsWhitespace(ch) || PDFCharIsLineEnding(ch)) + break; + } + SetPos(GetPos() - 1); int numMarkers = ReadEOLMarkers(GetPos()); if (m_WordSize == static_cast<unsigned int>(kEndObjStr.GetLength()) && @@ -730,15 +825,17 @@ } uint32_t CPDF_SyntaxParser::GetDirectNum() { - bool bIsNumber; - GetNextWordInternal(&bIsNumber); - if (!bIsNumber) + if (GetNextWordInternal() != WordType::kNumber) return 0; m_WordBuffer[m_WordSize] = 0; return FXSYS_atoui(reinterpret_cast<const char*>(m_WordBuffer)); } +RetainPtr<CPDF_ReadValidator> CPDF_SyntaxParser::GetValidator() const { + return m_pFileAccess; +} + bool CPDF_SyntaxParser::IsWholeWord(FX_FILESIZE startpos, FX_FILESIZE limit, ByteStringView tag, @@ -750,8 +847,8 @@ !PDFCharIsWhitespace(tag[taglen - 1]); uint8_t ch; - if (bCheckRight && startpos + (int32_t)taglen <= limit && - GetCharAt(startpos + (int32_t)taglen, ch)) { + if (bCheckRight && startpos + static_cast<int32_t>(taglen) <= limit && + GetCharAt(startpos + static_cast<int32_t>(taglen), ch)) { if (PDFCharIsNumeric(ch) || PDFCharIsOther(ch) || (checkKeyword && PDFCharIsDelimiter(ch))) { return false; @@ -775,7 +872,7 @@ FX_FILESIZE pos = m_Pos; int32_t offset = taglen - 1; - while (1) { + while (true) { if (limit && pos <= m_Pos - limit) return false; @@ -804,10 +901,10 @@ FX_FILESIZE CPDF_SyntaxParser::FindTag(ByteStringView tag) { const FX_FILESIZE startpos = GetPos(); const int32_t taglen = tag.GetLength(); - ASSERT(taglen > 0); + DCHECK_GT(taglen, 0); int32_t match = 0; - while (1) { + while (true) { uint8_t ch; if (!GetNextChar(ch)) return -1; @@ -820,7 +917,6 @@ match = ch == tag[0] ? 1 : 0; } } - return -1; } bool CPDF_SyntaxParser::IsPositionRead(FX_FILESIZE pos) const {
diff --git a/core/fpdfapi/parser/cpdf_syntax_parser.h b/core/fpdfapi/parser/cpdf_syntax_parser.h index d36aedf..ed79af2 100644 --- a/core/fpdfapi/parser/cpdf_syntax_parser.h +++ b/core/fpdfapi/parser/cpdf_syntax_parser.h
@@ -1,4 +1,4 @@ -// Copyright 2016 PDFium Authors. All rights reserved. +// Copyright 2016 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -7,14 +7,20 @@ #ifndef CORE_FPDFAPI_PARSER_CPDF_SYNTAX_PARSER_H_ #define CORE_FPDFAPI_PARSER_CPDF_SYNTAX_PARSER_H_ +#include <stdint.h> + #include <memory> #include <vector> #include "core/fpdfapi/parser/cpdf_stream.h" +#include "core/fxcrt/data_vector.h" +#include "core/fxcrt/fx_types.h" +#include "core/fxcrt/retain_ptr.h" #include "core/fxcrt/string_pool_template.h" +#include "core/fxcrt/unowned_ptr.h" #include "core/fxcrt/weak_ptr.h" +#include "third_party/base/span.h" -class CPDF_CryptoHandler; class CPDF_Dictionary; class CPDF_IndirectObjectHolder; class CPDF_Object; @@ -24,15 +30,19 @@ class CPDF_SyntaxParser { public: - enum class ParseType { kStrict, kLoose }; + enum class ParseType : bool { kStrict, kLoose }; + + struct WordResult { + ByteString word; + bool is_number; + }; static std::unique_ptr<CPDF_SyntaxParser> CreateForTesting( - const RetainPtr<IFX_SeekableReadStream>& pFileAccess, + RetainPtr<IFX_SeekableReadStream> pFileAccess, FX_FILESIZE HeaderOffset); - explicit CPDF_SyntaxParser( - const RetainPtr<IFX_SeekableReadStream>& pFileAccess); - CPDF_SyntaxParser(const RetainPtr<CPDF_ReadValidator>& pValidator, + explicit CPDF_SyntaxParser(RetainPtr<IFX_SeekableReadStream> pFileAccess); + CPDF_SyntaxParser(RetainPtr<CPDF_ReadValidator> pValidator, FX_FILESIZE HeaderOffset); ~CPDF_SyntaxParser(); @@ -44,23 +54,21 @@ void SetPos(FX_FILESIZE pos); RetainPtr<CPDF_Object> GetObjectBody(CPDF_IndirectObjectHolder* pObjList); - RetainPtr<CPDF_Object> GetIndirectObject(CPDF_IndirectObjectHolder* pObjList, ParseType parse_type); ByteString GetKeyword(); void ToNextLine(); void ToNextWord(); + void RecordingToNextWord(); bool BackwardsSearchToWord(ByteStringView word, FX_FILESIZE limit); FX_FILESIZE FindTag(ByteStringView tag); - bool ReadBlock(uint8_t* pBuf, uint32_t size); + bool ReadBlock(pdfium::span<uint8_t> buffer); bool GetCharAt(FX_FILESIZE pos, uint8_t& ch); - ByteString GetNextWord(bool* bIsNumber); - ByteString PeekNextWord(bool* bIsNumber); + WordResult GetNextWord(); + ByteString PeekNextWord(); - const RetainPtr<CPDF_ReadValidator>& GetValidator() const { - return m_pFileAccess; - } + RetainPtr<CPDF_ReadValidator> GetValidator() const; uint32_t GetDirectNum(); bool GetNextChar(uint8_t& ch); @@ -75,16 +83,22 @@ ByteString ReadString(); ByteString ReadHexString(); + void SetTrailerEnds(std::vector<unsigned int>* trailer_ends) { + m_TrailerEnds = trailer_ends; + } + private: + enum class WordType : bool { kWord, kNumber }; + friend class CPDF_DataAvail; friend class cpdf_syntax_parser_ReadHexString_Test; - static const int kParserMaxRecursionDepth = 64; + static constexpr int kParserMaxRecursionDepth = 64; static int s_CurrentRecursionDepth; bool ReadBlockAt(FX_FILESIZE read_pos); bool GetCharAtBackward(FX_FILESIZE pos, uint8_t* ch); - void GetNextWordInternal(bool* bIsNumber); + WordType GetNextWordInternal(); bool IsWholeWord(FX_FILESIZE startpos, FX_FILESIZE limit, ByteStringView tag, @@ -109,11 +123,14 @@ const FX_FILESIZE m_FileLen; FX_FILESIZE m_Pos = 0; WeakPtr<ByteStringPool> m_pPool; - std::vector<uint8_t> m_pFileBuf; + DataVector<uint8_t> m_pFileBuf; FX_FILESIZE m_BufOffset = 0; uint32_t m_WordSize = 0; - uint8_t m_WordBuffer[257]; + uint8_t m_WordBuffer[257] = {}; uint32_t m_ReadBufferSize = CPDF_Stream::kFileBufSize; + + // The syntax parser records traversed trailer end byte offsets here. + UnownedPtr<std::vector<unsigned int>> m_TrailerEnds; }; #endif // CORE_FPDFAPI_PARSER_CPDF_SYNTAX_PARSER_H_
diff --git a/core/fpdfapi/parser/cpdf_syntax_parser_unittest.cpp b/core/fpdfapi/parser/cpdf_syntax_parser_unittest.cpp index 53f0a17..94ab977 100644 --- a/core/fpdfapi/parser/cpdf_syntax_parser_unittest.cpp +++ b/core/fpdfapi/parser/cpdf_syntax_parser_unittest.cpp
@@ -1,24 +1,23 @@ -// Copyright 2016 PDFium Authors. All rights reserved. +// Copyright 2016 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include <limits> -#include <string> #include "core/fpdfapi/parser/cpdf_object.h" #include "core/fpdfapi/parser/cpdf_parser.h" #include "core/fpdfapi/parser/cpdf_syntax_parser.h" -#include "core/fxcrt/cfx_readonlymemorystream.h" +#include "core/fxcrt/cfx_read_only_span_stream.h" #include "core/fxcrt/fx_extension.h" #include "testing/gtest/include/gtest/gtest.h" #include "testing/utils/path_service.h" -TEST(cpdf_syntax_parser, ReadHexString) { +TEST(SyntaxParserTest, ReadHexString) { { // Empty string. static const uint8_t data[] = ""; - CPDF_SyntaxParser parser(pdfium::MakeRetain<CFX_ReadOnlyMemoryStream>( - pdfium::make_span(data, 0))); + CPDF_SyntaxParser parser( + pdfium::MakeRetain<CFX_ReadOnlySpanStream>(pdfium::make_span(data, 0))); EXPECT_EQ("", parser.ReadHexString()); EXPECT_EQ(0, parser.GetPos()); } @@ -26,8 +25,8 @@ { // Blank string. static const uint8_t data[] = " "; - CPDF_SyntaxParser parser(pdfium::MakeRetain<CFX_ReadOnlyMemoryStream>( - pdfium::make_span(data, 2))); + CPDF_SyntaxParser parser( + pdfium::MakeRetain<CFX_ReadOnlySpanStream>(pdfium::make_span(data, 2))); EXPECT_EQ("", parser.ReadHexString()); EXPECT_EQ(2, parser.GetPos()); } @@ -35,8 +34,8 @@ { // Skips unknown characters. static const uint8_t data[] = "z12b"; - CPDF_SyntaxParser parser(pdfium::MakeRetain<CFX_ReadOnlyMemoryStream>( - pdfium::make_span(data, 4))); + CPDF_SyntaxParser parser( + pdfium::MakeRetain<CFX_ReadOnlySpanStream>(pdfium::make_span(data, 4))); EXPECT_EQ("\x12\xb0", parser.ReadHexString()); EXPECT_EQ(4, parser.GetPos()); } @@ -44,7 +43,7 @@ { // Skips unknown characters. static const uint8_t data[] = "*<&*#$^&@1"; - CPDF_SyntaxParser parser(pdfium::MakeRetain<CFX_ReadOnlyMemoryStream>( + CPDF_SyntaxParser parser(pdfium::MakeRetain<CFX_ReadOnlySpanStream>( pdfium::make_span(data, 10))); EXPECT_EQ("\x10", parser.ReadHexString()); EXPECT_EQ(10, parser.GetPos()); @@ -53,8 +52,8 @@ { // Skips unknown characters. static const uint8_t data[] = "\x80zab"; - CPDF_SyntaxParser parser(pdfium::MakeRetain<CFX_ReadOnlyMemoryStream>( - pdfium::make_span(data, 4))); + CPDF_SyntaxParser parser( + pdfium::MakeRetain<CFX_ReadOnlySpanStream>(pdfium::make_span(data, 4))); EXPECT_EQ("\xab", parser.ReadHexString()); EXPECT_EQ(4, parser.GetPos()); } @@ -62,8 +61,8 @@ { // Skips unknown characters. static const uint8_t data[] = "\xffzab"; - CPDF_SyntaxParser parser(pdfium::MakeRetain<CFX_ReadOnlyMemoryStream>( - pdfium::make_span(data, 4))); + CPDF_SyntaxParser parser( + pdfium::MakeRetain<CFX_ReadOnlySpanStream>(pdfium::make_span(data, 4))); EXPECT_EQ("\xab", parser.ReadHexString()); EXPECT_EQ(4, parser.GetPos()); } @@ -71,8 +70,8 @@ { // Regular conversion. static const uint8_t data[] = "1A2b>abcd"; - CPDF_SyntaxParser parser(pdfium::MakeRetain<CFX_ReadOnlyMemoryStream>( - pdfium::make_span(data, 9))); + CPDF_SyntaxParser parser( + pdfium::MakeRetain<CFX_ReadOnlySpanStream>(pdfium::make_span(data, 9))); EXPECT_EQ("\x1a\x2b", parser.ReadHexString()); EXPECT_EQ(5, parser.GetPos()); } @@ -80,17 +79,14 @@ { // Position out of bounds. static const uint8_t data[] = "12ab>"; - CPDF_SyntaxParser parser(pdfium::MakeRetain<CFX_ReadOnlyMemoryStream>( - pdfium::make_span(data, 5))); + CPDF_SyntaxParser parser( + pdfium::MakeRetain<CFX_ReadOnlySpanStream>(pdfium::make_span(data, 5))); parser.SetPos(5); EXPECT_EQ("", parser.ReadHexString()); parser.SetPos(6); EXPECT_EQ("", parser.ReadHexString()); - parser.SetPos(-1); - EXPECT_EQ("", parser.ReadHexString()); - parser.SetPos(std::numeric_limits<FX_FILESIZE>::max()); EXPECT_EQ("", parser.ReadHexString()); @@ -102,8 +98,8 @@ { // Missing ending >. static const uint8_t data[] = "1A2b"; - CPDF_SyntaxParser parser(pdfium::MakeRetain<CFX_ReadOnlyMemoryStream>( - pdfium::make_span(data, 4))); + CPDF_SyntaxParser parser( + pdfium::MakeRetain<CFX_ReadOnlySpanStream>(pdfium::make_span(data, 4))); EXPECT_EQ("\x1a\x2b", parser.ReadHexString()); EXPECT_EQ(4, parser.GetPos()); } @@ -111,8 +107,8 @@ { // Missing ending >. static const uint8_t data[] = "12abz"; - CPDF_SyntaxParser parser(pdfium::MakeRetain<CFX_ReadOnlyMemoryStream>( - pdfium::make_span(data, 5))); + CPDF_SyntaxParser parser( + pdfium::MakeRetain<CFX_ReadOnlySpanStream>(pdfium::make_span(data, 5))); EXPECT_EQ("\x12\xab", parser.ReadHexString()); EXPECT_EQ(5, parser.GetPos()); } @@ -120,8 +116,8 @@ { // Uneven number of bytes. static const uint8_t data[] = "1A2>asdf"; - CPDF_SyntaxParser parser(pdfium::MakeRetain<CFX_ReadOnlyMemoryStream>( - pdfium::make_span(data, 8))); + CPDF_SyntaxParser parser( + pdfium::MakeRetain<CFX_ReadOnlySpanStream>(pdfium::make_span(data, 8))); EXPECT_EQ("\x1a\x20", parser.ReadHexString()); EXPECT_EQ(4, parser.GetPos()); } @@ -129,8 +125,8 @@ { // Uneven number of bytes. static const uint8_t data[] = "1A2zasdf"; - CPDF_SyntaxParser parser(pdfium::MakeRetain<CFX_ReadOnlyMemoryStream>( - pdfium::make_span(data, 8))); + CPDF_SyntaxParser parser( + pdfium::MakeRetain<CFX_ReadOnlySpanStream>(pdfium::make_span(data, 8))); EXPECT_EQ("\x1a\x2a\xdf", parser.ReadHexString()); EXPECT_EQ(8, parser.GetPos()); } @@ -138,25 +134,25 @@ { // Just ending character. static const uint8_t data[] = ">"; - CPDF_SyntaxParser parser(pdfium::MakeRetain<CFX_ReadOnlyMemoryStream>( - pdfium::make_span(data, 1))); + CPDF_SyntaxParser parser( + pdfium::MakeRetain<CFX_ReadOnlySpanStream>(pdfium::make_span(data, 1))); EXPECT_EQ("", parser.ReadHexString()); EXPECT_EQ(1, parser.GetPos()); } } -TEST(cpdf_syntax_parser, GetInvalidReference) { +TEST(SyntaxParserTest, GetInvalidReference) { // Data with a reference with number CPDF_Object::kInvalidObjNum static const uint8_t data[] = "4294967295 0 R"; - CPDF_SyntaxParser parser(pdfium::MakeRetain<CFX_ReadOnlyMemoryStream>( - pdfium::make_span(data, 14))); + CPDF_SyntaxParser parser( + pdfium::MakeRetain<CFX_ReadOnlySpanStream>(pdfium::make_span(data, 14))); RetainPtr<CPDF_Object> ref = parser.GetObjectBody(nullptr); EXPECT_FALSE(ref); } -TEST(cpdf_syntax_parser, PeekNextWord) { +TEST(SyntaxParserTest, PeekNextWord) { static const uint8_t data[] = " WORD "; - CPDF_SyntaxParser parser(pdfium::MakeRetain<CFX_ReadOnlyMemoryStream>(data)); - EXPECT_EQ("WORD", parser.PeekNextWord(nullptr)); - EXPECT_EQ("WORD", parser.GetNextWord(nullptr)); + CPDF_SyntaxParser parser(pdfium::MakeRetain<CFX_ReadOnlySpanStream>(data)); + EXPECT_EQ("WORD", parser.PeekNextWord()); + EXPECT_EQ("WORD", parser.GetNextWord().word); }
diff --git a/core/fpdfapi/parser/cpdf_test_document.cpp b/core/fpdfapi/parser/cpdf_test_document.cpp new file mode 100644 index 0000000..d13103f --- /dev/null +++ b/core/fpdfapi/parser/cpdf_test_document.cpp
@@ -0,0 +1,19 @@ +// Copyright 2022 The PDFium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "core/fpdfapi/parser/cpdf_test_document.h" + +#include <memory> +#include <utility> + +#include "core/fpdfapi/page/cpdf_docpagedata.h" +#include "core/fpdfapi/render/cpdf_docrenderdata.h" + +CPDF_TestDocument::CPDF_TestDocument() + : CPDF_Document(std::make_unique<CPDF_DocRenderData>(), + std::make_unique<CPDF_DocPageData>()) {} + +void CPDF_TestDocument::SetRoot(RetainPtr<CPDF_Dictionary> root) { + SetRootForTesting(std::move(root)); +}
diff --git a/core/fpdfapi/parser/cpdf_test_document.h b/core/fpdfapi/parser/cpdf_test_document.h new file mode 100644 index 0000000..f50dc8e --- /dev/null +++ b/core/fpdfapi/parser/cpdf_test_document.h
@@ -0,0 +1,20 @@ +// Copyright 2022 The PDFium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CORE_FPDFAPI_PARSER_CPDF_TEST_DOCUMENT_H_ +#define CORE_FPDFAPI_PARSER_CPDF_TEST_DOCUMENT_H_ + +#include "core/fpdfapi/parser/cpdf_document.h" +#include "core/fxcrt/retain_ptr.h" + +class CPDF_Dictionary; + +class CPDF_TestDocument : public CPDF_Document { + public: + CPDF_TestDocument(); + + void SetRoot(RetainPtr<CPDF_Dictionary> root); +}; + +#endif // CORE_FPDFAPI_PARSER_CPDF_TEST_DOCUMENT_H_
diff --git a/core/fpdfapi/parser/fpdf_parser_decode.cpp b/core/fpdfapi/parser/fpdf_parser_decode.cpp index 7074061..6f29b7a 100644 --- a/core/fpdfapi/parser/fpdf_parser_decode.cpp +++ b/core/fpdfapi/parser/fpdf_parser_decode.cpp
@@ -1,4 +1,4 @@ -// Copyright 2014 PDFium Authors. All rights reserved. +// Copyright 2014 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -6,12 +6,11 @@ #include "core/fpdfapi/parser/fpdf_parser_decode.h" +#include <ctype.h> #include <limits.h> #include <algorithm> -#include <sstream> #include <utility> -#include <vector> #include "constants/stream_dict_common.h" #include "core/fpdfapi/parser/cpdf_array.h" @@ -19,12 +18,12 @@ #include "core/fpdfapi/parser/fpdf_parser_utility.h" #include "core/fxcodec/fax/faxmodule.h" #include "core/fxcodec/flate/flatemodule.h" -#include "core/fxcodec/fx_codec.h" #include "core/fxcodec/scanlinedecoder.h" #include "core/fxcrt/fx_extension.h" #include "core/fxcrt/fx_safe_types.h" -#include "third_party/base/numerics/safe_math.h" -#include "third_party/base/stl_util.h" +#include "core/fxcrt/span_util.h" +#include "third_party/base/check.h" +#include "third_party/base/containers/contains.h" namespace { @@ -42,7 +41,7 @@ if (Colors < 0 || BitsPerComponent < 0 || Columns < 0) return false; - pdfium::base::CheckedNumeric<int> check = Columns; + FX_SAFE_INT32 check = Columns; check *= Colors; check *= BitsPerComponent; if (!check.IsValid()) @@ -57,7 +56,7 @@ } // namespace -const uint16_t PDFDocEncoding[256] = { +const uint16_t kPDFDocEncoding[256] = { 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, 0x0008, 0x0009, 0x000a, 0x000b, 0x000c, 0x000d, 0x000e, 0x000f, 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, 0x02d8, 0x02c7, 0x02c6, @@ -94,8 +93,10 @@ return true; for (size_t i = 0; i < count; ++i) { - if (!pDecoders->GetObjectAt(i)->IsName()) + RetainPtr<const CPDF_Object> object = pDecoders->GetDirectObjectAt(i); + if (!object || !object->IsName()) { return false; + } } if (count == 1) @@ -106,7 +107,7 @@ "FlateDecode", "Fl", "LZWDecode", "LZW", "ASCII85Decode", "A85", "ASCIIHexDecode", "AHx", "RunLengthDecode", "RL"}; for (size_t i = 0; i < count - 1; ++i) { - if (!pdfium::ContainsValue(kValidDecoders, pDecoders->GetStringAt(i))) + if (!pdfium::Contains(kValidDecoders, pDecoders->GetByteStringAt(i))) return false; } return true; @@ -219,7 +220,7 @@ ++i; break; } - if (!std::isxdigit(ch)) + if (!isxdigit(ch)) continue; int digit = FXSYS_HexCharToInt(ch); @@ -273,18 +274,17 @@ if (buf_left < copy_len) { uint32_t delta = copy_len - buf_left; copy_len = buf_left; - memset(&dest_span[dest_count + copy_len], '\0', delta); + fxcrt::spanclr(dest_span.subspan(dest_count + copy_len, delta)); } auto copy_span = src_span.subspan(i + 1, copy_len); - memcpy(&dest_span[dest_count], copy_span.data(), copy_span.size()); + fxcrt::spancpy(dest_span.subspan(dest_count), copy_span); dest_count += src_span[i] + 1; i += src_span[i] + 2; } else { - int fill = 0; - if (i < src_span.size() - 1) - fill = src_span[i + 1]; - memset(&dest_span[dest_count], fill, 257 - src_span[i]); - dest_count += 257 - src_span[i]; + const uint8_t fill = i < src_span.size() - 1 ? src_span[i + 1] : 0; + const size_t fill_size = 257 - src_span[i]; + fxcrt::spanset(dest_span.subspan(dest_count, fill_size), fill); + dest_count += fill_size; i += 2; } } @@ -365,43 +365,46 @@ estimated_size, dest_buf, dest_size); } -Optional<std::vector<std::pair<ByteString, const CPDF_Object*>>> -GetDecoderArray(const CPDF_Dictionary* pDict) { - const CPDF_Object* pDecoder = pDict->GetDirectObjectFor("Filter"); - if (!pDecoder || (!pDecoder->IsArray() && !pDecoder->IsName())) - return {}; +absl::optional<DecoderArray> GetDecoderArray( + RetainPtr<const CPDF_Dictionary> pDict) { + RetainPtr<const CPDF_Object> pFilter = pDict->GetDirectObjectFor("Filter"); + if (!pFilter) + return DecoderArray(); - const CPDF_Object* pParams = + if (!pFilter->IsArray() && !pFilter->IsName()) + return absl::nullopt; + + RetainPtr<const CPDF_Object> pParams = pDict->GetDirectObjectFor(pdfium::stream::kDecodeParms); - std::vector<std::pair<ByteString, const CPDF_Object*>> decoder_array; - if (const CPDF_Array* pDecoders = pDecoder->AsArray()) { + DecoderArray decoder_array; + if (const CPDF_Array* pDecoders = pFilter->AsArray()) { if (!ValidateDecoderPipeline(pDecoders)) - return {}; + return absl::nullopt; - const CPDF_Array* pParamsArray = ToArray(pParams); + RetainPtr<const CPDF_Array> pParamsArray = ToArray(pParams); for (size_t i = 0; i < pDecoders->size(); ++i) { - decoder_array.push_back( - {pDecoders->GetStringAt(i), - pParamsArray ? pParamsArray->GetDictAt(i) : nullptr}); + decoder_array.emplace_back( + pDecoders->GetByteStringAt(i), + pParamsArray ? pParamsArray->GetDictAt(i) : nullptr); } } else { - decoder_array.push_back( - {pDecoder->GetString(), pParams ? pParams->GetDict() : nullptr}); + DCHECK(pFilter->IsName()); + decoder_array.emplace_back(pFilter->GetString(), + pParams ? pParams->GetDict() : nullptr); } return decoder_array; } -bool PDF_DataDecode( - pdfium::span<const uint8_t> src_span, - uint32_t last_estimated_size, - bool bImageAcc, - const std::vector<std::pair<ByteString, const CPDF_Object*>>& decoder_array, - std::unique_ptr<uint8_t, FxFreeDeleter>* dest_buf, - uint32_t* dest_size, - ByteString* ImageEncoding, - RetainPtr<const CPDF_Dictionary>* pImageParams) { +bool PDF_DataDecode(pdfium::span<const uint8_t> src_span, + uint32_t last_estimated_size, + bool bImageAcc, + const DecoderArray& decoder_array, + std::unique_ptr<uint8_t, FxFreeDeleter>* dest_buf, + uint32_t* dest_size, + ByteString* ImageEncoding, + RetainPtr<const CPDF_Dictionary>* pImageParams) { std::unique_ptr<uint8_t, FxFreeDeleter> result; // May be changed to point to |result| in the for-loop below. So put it below // |result| and let it get destroyed first. @@ -410,7 +413,8 @@ for (size_t i = 0; i < nSize; ++i) { int estimated_size = i == nSize - 1 ? last_estimated_size : 0; ByteString decoder = decoder_array[i].first; - const CPDF_Dictionary* pParam = ToDictionary(decoder_array[i].second); + RetainPtr<const CPDF_Dictionary> pParam = + ToDictionary(decoder_array[i].second); std::unique_ptr<uint8_t, FxFreeDeleter> new_buf; uint32_t new_size = 0xFFFFFFFF; uint32_t offset = FX_INVALID_OFFSET; @@ -421,7 +425,7 @@ *ImageEncoding = "FlateDecode"; *dest_buf = std::move(result); *dest_size = last_span.size(); - pImageParams->Reset(pParam); + *pImageParams = std::move(pParam); return true; } offset = FlateOrLZWDecode(false, last_span, pParam, estimated_size, @@ -438,7 +442,7 @@ *ImageEncoding = "RunLengthDecode"; *dest_buf = std::move(result); *dest_size = last_span.size(); - pImageParams->Reset(pParam); + *pImageParams = std::move(pParam); return true; } offset = RunLengthDecode(last_span, &new_buf, &new_size); @@ -449,7 +453,7 @@ else if (decoder == "CCF") decoder = "CCITTFaxDecode"; *ImageEncoding = std::move(decoder); - pImageParams->Reset(pParam); + *pImageParams = std::move(pParam); *dest_buf = std::move(result); *dest_size = last_span.size(); return true; @@ -506,14 +510,14 @@ } else { pdfium::span<wchar_t> dest_buf = result.GetBuffer(span.size()); for (size_t i = 0; i < span.size(); ++i) - dest_buf[i] = PDFDocEncoding[span[i]]; + dest_buf[i] = kPDFDocEncoding[span[i]]; dest_pos = span.size(); } result.ReleaseBuffer(dest_pos); return result; } -ByteString PDF_EncodeText(const WideString& str) { +ByteString PDF_EncodeText(WideStringView str) { size_t i = 0; size_t len = str.GetLength(); ByteString result; @@ -522,7 +526,7 @@ for (i = 0; i < len; ++i) { int code; for (code = 0; code < 256; ++code) { - if (PDFDocEncoding[code] == str[i]) + if (kPDFDocEncoding[code] == str[i]) break; } if (code == 256) @@ -556,44 +560,44 @@ return result; } -ByteString PDF_EncodeString(const ByteString& src, bool bHex) { - std::ostringstream result; - int srclen = src.GetLength(); - if (bHex) { - result << '<'; - for (int i = 0; i < srclen; ++i) { - char buf[2]; - FXSYS_IntToTwoHexChars(src[i], buf); - result << buf[0]; - result << buf[1]; - } - result << '>'; - return ByteString(result); - } - result << '('; - for (int i = 0; i < srclen; ++i) { +ByteString PDF_EncodeString(ByteStringView src) { + ByteString result; + result.Reserve(src.GetLength() + 2); + result += '('; + for (size_t i = 0; i < src.GetLength(); ++i) { uint8_t ch = src[i]; if (ch == 0x0a) { - result << "\\n"; + result += "\\n"; continue; } if (ch == 0x0d) { - result << "\\r"; + result += "\\r"; continue; } if (ch == ')' || ch == '\\' || ch == '(') - result << '\\'; - result << static_cast<char>(ch); + result += '\\'; + result += static_cast<char>(ch); } - result << ')'; - return ByteString(result); + result += ')'; + return result; } -bool FlateEncode(pdfium::span<const uint8_t> src_span, - std::unique_ptr<uint8_t, FxFreeDeleter>* dest_buf, - uint32_t* dest_size) { - return FlateModule::Encode(src_span.data(), src_span.size(), dest_buf, - dest_size); +ByteString PDF_HexEncodeString(ByteStringView src) { + ByteString result; + result.Reserve(2 * src.GetLength() + 2); + result += '<'; + for (size_t i = 0; i < src.GetLength(); ++i) { + char buf[2]; + FXSYS_IntToTwoHexChars(src[i], buf); + result += buf[0]; + result += buf[1]; + } + result += '>'; + return result; +} + +DataVector<uint8_t> FlateEncode(pdfium::span<const uint8_t> src_span) { + return FlateModule::Encode(src_span); } uint32_t FlateDecode(pdfium::span<const uint8_t> src_span,
diff --git a/core/fpdfapi/parser/fpdf_parser_decode.h b/core/fpdfapi/parser/fpdf_parser_decode.h index ebb64e6..a437455 100644 --- a/core/fpdfapi/parser/fpdf_parser_decode.h +++ b/core/fpdfapi/parser/fpdf_parser_decode.h
@@ -1,4 +1,4 @@ -// Copyright 2016 PDFium Authors. All rights reserved. +// Copyright 2016 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -7,14 +7,17 @@ #ifndef CORE_FPDFAPI_PARSER_FPDF_PARSER_DECODE_H_ #define CORE_FPDFAPI_PARSER_FPDF_PARSER_DECODE_H_ +#include <stdint.h> + #include <memory> #include <utility> #include <vector> +#include "core/fxcrt/data_vector.h" #include "core/fxcrt/fx_memory_wrappers.h" #include "core/fxcrt/fx_string.h" -#include "core/fxcrt/unowned_ptr.h" -#include "third_party/base/optional.h" +#include "core/fxcrt/retain_ptr.h" +#include "third_party/abseil-cpp/absl/types/optional.h" #include "third_party/base/span.h" class CPDF_Array; @@ -26,13 +29,14 @@ } // Indexed by 8-bit char code, contains unicode code points. -extern const uint16_t PDFDocEncoding[256]; +extern const uint16_t kPDFDocEncoding[256]; bool ValidateDecoderPipeline(const CPDF_Array* pDecoders); -ByteString PDF_EncodeString(const ByteString& src, bool bHex); +ByteString PDF_EncodeString(ByteStringView src); +ByteString PDF_HexEncodeString(ByteStringView src); WideString PDF_DecodeText(pdfium::span<const uint8_t> span); -ByteString PDF_EncodeText(const WideString& str); +ByteString PDF_EncodeText(WideStringView str); std::unique_ptr<fxcodec::ScanlineDecoder> CreateFaxDecoder( pdfium::span<const uint8_t> src_span, @@ -48,9 +52,7 @@ int bpc, const CPDF_Dictionary* pParams); -bool FlateEncode(pdfium::span<const uint8_t> src_span, - std::unique_ptr<uint8_t, FxFreeDeleter>* dest_buf, - uint32_t* dest_size); +DataVector<uint8_t> FlateEncode(pdfium::span<const uint8_t> src_span); uint32_t FlateDecode(pdfium::span<const uint8_t> src_span, std::unique_ptr<uint8_t, FxFreeDeleter>* dest_buf, @@ -75,17 +77,23 @@ std::unique_ptr<uint8_t, FxFreeDeleter>* dest_buf, uint32_t* dest_size); -Optional<std::vector<std::pair<ByteString, const CPDF_Object*>>> -GetDecoderArray(const CPDF_Dictionary* pDict); +// Returns absl::nullopt if the filter in |pDict| is the wrong type or an +// invalid decoder pipeline. +// Returns an empty vector if there is no filter, or if the filter is an empty +// array. +// Otherwise, returns a vector of decoders. +using DecoderArray = + std::vector<std::pair<ByteString, RetainPtr<const CPDF_Object>>>; +absl::optional<DecoderArray> GetDecoderArray( + RetainPtr<const CPDF_Dictionary> pDict); -bool PDF_DataDecode( - pdfium::span<const uint8_t> src_span, - uint32_t estimated_size, - bool bImageAcc, - const std::vector<std::pair<ByteString, const CPDF_Object*>>& decoder_array, - std::unique_ptr<uint8_t, FxFreeDeleter>* dest_buf, - uint32_t* dest_size, - ByteString* ImageEncoding, - RetainPtr<const CPDF_Dictionary>* pImageParams); +bool PDF_DataDecode(pdfium::span<const uint8_t> src_span, + uint32_t estimated_size, + bool bImageAcc, + const DecoderArray& decoder_array, + std::unique_ptr<uint8_t, FxFreeDeleter>* dest_buf, + uint32_t* dest_size, + ByteString* ImageEncoding, + RetainPtr<const CPDF_Dictionary>* pImageParams); #endif // CORE_FPDFAPI_PARSER_FPDF_PARSER_DECODE_H_
diff --git a/core/fpdfapi/parser/fpdf_parser_decode_embeddertest.cpp b/core/fpdfapi/parser/fpdf_parser_decode_embeddertest.cpp index 32a34db..e5b8b05 100644 --- a/core/fpdfapi/parser/fpdf_parser_decode_embeddertest.cpp +++ b/core/fpdfapi/parser/fpdf_parser_decode_embeddertest.cpp
@@ -1,136 +1,48 @@ -// Copyright 2015 PDFium Authors. All rights reserved. +// Copyright 2015 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include <cstring> -#include <memory> -#include <string> - #include "build/build_config.h" #include "core/fpdfapi/parser/fpdf_parser_decode.h" -#include "core/fxcrt/fx_memory_wrappers.h" #include "public/cpp/fpdf_scopers.h" #include "testing/embedder_test.h" +#include "testing/embedder_test_constants.h" #include "testing/gtest/include/gtest/gtest.h" #include "testing/test_support.h" using FPDFParserDecodeEmbedderTest = EmbedderTest; +using pdfium::kBlankPage612By792Checksum; -// NOTE: python's zlib.compress() and zlib.decompress() may be useful for -// external validation of the FlateEncode/FlateDecode test cases. - -TEST_F(FPDFParserDecodeEmbedderTest, FlateEncode) { - static const pdfium::StrFuncTestData flate_encode_cases[] = { - STR_IN_OUT_CASE("", "\x78\x9c\x03\x00\x00\x00\x00\x01"), - STR_IN_OUT_CASE(" ", "\x78\x9c\x53\x00\x00\x00\x21\x00\x21"), - STR_IN_OUT_CASE("123", "\x78\x9c\x33\x34\x32\x06\x00\01\x2d\x00\x97"), - STR_IN_OUT_CASE("\x00\xff", "\x78\x9c\x63\xf8\x0f\x00\x01\x01\x01\x00"), - STR_IN_OUT_CASE( - "1 0 0 -1 29 763 cm\n0 0 555 735 re\nW n\nq\n0 0 555 734.394 re\n" - "W n\nq\n0.8009 0 0 0.8009 0 0 cm\n1 1 1 RG 1 1 1 rg\n/G0 gs\n" - "0 0 693 917 re\nf\nQ\nQ\n", - "\x78\x9c\x33\x54\x30\x00\x42\x5d\x43\x05\x23\x4b\x05\x73\x33\x63" - "\x85\xe4\x5c\x2e\x90\x80\xa9\xa9\xa9\x82\xb9\xb1\xa9\x42\x51\x2a" - "\x57\xb8\x42\x1e\x57\x21\x92\xa0\x89\x9e\xb1\xa5\x09\x92\x84\x9e" - "\x85\x81\x81\x25\xd8\x14\x24\x26\xd0\x18\x43\x05\x10\x0c\x72\x57" - "\x80\x30\x8a\xd2\xb9\xf4\xdd\x0d\x14\xd2\x8b\xc1\x46\x99\x59\x1a" - "\x2b\x58\x1a\x9a\x83\x8c\x49\xe3\x0a\x04\x42\x00\x37\x4c\x1b\x42"), - }; - - for (size_t i = 0; i < FX_ArraySize(flate_encode_cases); ++i) { - const pdfium::StrFuncTestData& data = flate_encode_cases[i]; - std::unique_ptr<uint8_t, FxFreeDeleter> buf; - uint32_t buf_size; - EXPECT_TRUE(FlateEncode({data.input, data.input_size}, &buf, &buf_size)); - ASSERT_TRUE(buf); - EXPECT_EQ(data.expected_size, buf_size) << " for case " << i; - if (data.expected_size != buf_size) - continue; - EXPECT_EQ(0, memcmp(data.expected, buf.get(), data.expected_size)) - << " for case " << i; - } -} - -TEST_F(FPDFParserDecodeEmbedderTest, FlateDecode) { - static const pdfium::DecodeTestData flate_decode_cases[] = { - STR_IN_OUT_CASE("", "", 0), - STR_IN_OUT_CASE("preposterous nonsense", "", 2), - STR_IN_OUT_CASE("\x78\x9c\x03\x00\x00\x00\x00\x01", "", 8), - STR_IN_OUT_CASE("\x78\x9c\x53\x00\x00\x00\x21\x00\x21", " ", 9), - STR_IN_OUT_CASE("\x78\x9c\x33\x34\x32\x06\x00\01\x2d\x00\x97", "123", 11), - STR_IN_OUT_CASE("\x78\x9c\x63\xf8\x0f\x00\x01\x01\x01\x00", "\x00\xff", - 10), - STR_IN_OUT_CASE( - "\x78\x9c\x33\x54\x30\x00\x42\x5d\x43\x05\x23\x4b\x05\x73\x33\x63" - "\x85\xe4\x5c\x2e\x90\x80\xa9\xa9\xa9\x82\xb9\xb1\xa9\x42\x51\x2a" - "\x57\xb8\x42\x1e\x57\x21\x92\xa0\x89\x9e\xb1\xa5\x09\x92\x84\x9e" - "\x85\x81\x81\x25\xd8\x14\x24\x26\xd0\x18\x43\x05\x10\x0c\x72\x57" - "\x80\x30\x8a\xd2\xb9\xf4\xdd\x0d\x14\xd2\x8b\xc1\x46\x99\x59\x1a" - "\x2b\x58\x1a\x9a\x83\x8c\x49\xe3\x0a\x04\x42\x00\x37\x4c\x1b\x42", - "1 0 0 -1 29 763 cm\n0 0 555 735 re\nW n\nq\n0 0 555 734.394 re\n" - "W n\nq\n0.8009 0 0 0.8009 0 0 cm\n1 1 1 RG 1 1 1 rg\n/G0 gs\n" - "0 0 693 917 re\nf\nQ\nQ\n", - 96), - }; - - for (size_t i = 0; i < FX_ArraySize(flate_decode_cases); ++i) { - const pdfium::DecodeTestData& data = flate_decode_cases[i]; - std::unique_ptr<uint8_t, FxFreeDeleter> buf; - uint32_t buf_size; - EXPECT_EQ(data.processed_size, - FlateDecode({data.input, data.input_size}, &buf, &buf_size)) - << " for case " << i; - ASSERT_TRUE(buf); - EXPECT_EQ(data.expected_size, buf_size) << " for case " << i; - if (data.expected_size != buf_size) - continue; - EXPECT_EQ(0, memcmp(data.expected, buf.get(), data.expected_size)) - << " for case " << i; - } -} - -TEST_F(FPDFParserDecodeEmbedderTest, Bug_552046) { +TEST_F(FPDFParserDecodeEmbedderTest, Bug552046) { // Tests specifying multiple image filters for a stream. Should not cause a // crash when rendered. - EXPECT_TRUE(OpenDocument("bug_552046.pdf")); + ASSERT_TRUE(OpenDocument("bug_552046.pdf")); FPDF_PAGE page = LoadPage(0); ASSERT_TRUE(page); ScopedFPDFBitmap bitmap = RenderLoadedPage(page); - CompareBitmap(bitmap.get(), 612, 792, "1940568c9ba33bac5d0b1ee9558c76b3"); + CompareBitmap(bitmap.get(), 612, 792, kBlankPage612By792Checksum); UnloadPage(page); } -TEST_F(FPDFParserDecodeEmbedderTest, Bug_555784) { +TEST_F(FPDFParserDecodeEmbedderTest, Bug555784) { // Tests bad input to the run length decoder that caused a heap overflow. // Should not cause a crash when rendered. - EXPECT_TRUE(OpenDocument("bug_555784.pdf")); + ASSERT_TRUE(OpenDocument("bug_555784.pdf")); FPDF_PAGE page = LoadPage(0); ASSERT_TRUE(page); ScopedFPDFBitmap bitmap = RenderLoadedPage(page); - CompareBitmap(bitmap.get(), 612, 792, "1940568c9ba33bac5d0b1ee9558c76b3"); + CompareBitmap(bitmap.get(), 612, 792, kBlankPage612By792Checksum); UnloadPage(page); } -// TODO(crbug.com/pdfium/11): Fix this test and enable. -#if defined(_SKIA_SUPPORT_) || defined(_SKIA_SUPPORT_PATHS_) -#define MAYBE_Bug_455199 DISABLED_Bug_455199 -#else -#define MAYBE_Bug_455199 Bug_455199 -#endif -TEST_F(FPDFParserDecodeEmbedderTest, MAYBE_Bug_455199) { +TEST_F(FPDFParserDecodeEmbedderTest, Bug455199) { // Tests object numbers with a value > 01000000. // Should open successfully. - EXPECT_TRUE(OpenDocument("bug_455199.pdf")); + ASSERT_TRUE(OpenDocument("bug_455199.pdf")); FPDF_PAGE page = LoadPage(0); ASSERT_TRUE(page); ScopedFPDFBitmap bitmap = RenderLoadedPage(page); -#if defined(OS_MACOSX) - const char kExpectedMd5sum[] = "b90475ca64d1348c3bf5e2b77ad9187a"; -#elif defined(OS_WIN) - const char kExpectedMd5sum[] = "795b7ce1626931aa06af0fa23b7d80bb"; -#else - const char kExpectedMd5sum[] = "2baa4c0e1758deba1b9c908e1fbd04ed"; -#endif - CompareBitmap(bitmap.get(), 200, 200, kExpectedMd5sum); + + CompareBitmap(bitmap.get(), 200, 200, pdfium::HelloWorldChecksum()); UnloadPage(page); }
diff --git a/core/fpdfapi/parser/fpdf_parser_decode_unittest.cpp b/core/fpdfapi/parser/fpdf_parser_decode_unittest.cpp index 311226f..2c2074b 100644 --- a/core/fpdfapi/parser/fpdf_parser_decode_unittest.cpp +++ b/core/fpdfapi/parser/fpdf_parser_decode_unittest.cpp
@@ -1,17 +1,22 @@ -// Copyright 2015 PDFium Authors. All rights reserved. +// Copyright 2015 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "core/fpdfapi/parser/fpdf_parser_decode.h" +#include <iterator> + #include "core/fpdfapi/parser/cpdf_array.h" +#include "core/fpdfapi/parser/cpdf_dictionary.h" +#include "core/fpdfapi/parser/cpdf_indirect_object_holder.h" #include "core/fpdfapi/parser/cpdf_name.h" +#include "core/fpdfapi/parser/cpdf_reference.h" #include "core/fpdfapi/parser/cpdf_string.h" #include "core/fxcrt/fx_memory_wrappers.h" #include "testing/gtest/include/gtest/gtest.h" #include "testing/test_support.h" -TEST(fpdf_parser_decode, ValidateDecoderPipeline) { +TEST(ParserDecodeTest, ValidateDecoderPipeline) { { // Empty decoder list is always valid. auto decoders = pdfium::MakeRetain<CPDF_Array>(); @@ -20,99 +25,221 @@ { // 1 decoder is almost always valid. auto decoders = pdfium::MakeRetain<CPDF_Array>(); - decoders->AddNew<CPDF_Name>("FlateEncode"); + decoders->AppendNew<CPDF_Name>("FlateEncode"); EXPECT_TRUE(ValidateDecoderPipeline(decoders.Get())); } { // 1 decoder is almost always valid, even with an unknown decoder. auto decoders = pdfium::MakeRetain<CPDF_Array>(); - decoders->AddNew<CPDF_Name>("FooBar"); + decoders->AppendNew<CPDF_Name>("FooBar"); EXPECT_TRUE(ValidateDecoderPipeline(decoders.Get())); } { // Valid 2 decoder pipeline. auto decoders = pdfium::MakeRetain<CPDF_Array>(); - decoders->AddNew<CPDF_Name>("AHx"); - decoders->AddNew<CPDF_Name>("LZWDecode"); + decoders->AppendNew<CPDF_Name>("AHx"); + decoders->AppendNew<CPDF_Name>("LZWDecode"); EXPECT_TRUE(ValidateDecoderPipeline(decoders.Get())); } { // Valid 2 decoder pipeline. auto decoders = pdfium::MakeRetain<CPDF_Array>(); - decoders->AddNew<CPDF_Name>("ASCII85Decode"); - decoders->AddNew<CPDF_Name>("ASCII85Decode"); + decoders->AppendNew<CPDF_Name>("ASCII85Decode"); + decoders->AppendNew<CPDF_Name>("ASCII85Decode"); EXPECT_TRUE(ValidateDecoderPipeline(decoders.Get())); } { // Valid 5 decoder pipeline. auto decoders = pdfium::MakeRetain<CPDF_Array>(); - decoders->AddNew<CPDF_Name>("ASCII85Decode"); - decoders->AddNew<CPDF_Name>("A85"); - decoders->AddNew<CPDF_Name>("RunLengthDecode"); - decoders->AddNew<CPDF_Name>("FlateDecode"); - decoders->AddNew<CPDF_Name>("RL"); + decoders->AppendNew<CPDF_Name>("ASCII85Decode"); + decoders->AppendNew<CPDF_Name>("A85"); + decoders->AppendNew<CPDF_Name>("RunLengthDecode"); + decoders->AppendNew<CPDF_Name>("FlateDecode"); + decoders->AppendNew<CPDF_Name>("RL"); EXPECT_TRUE(ValidateDecoderPipeline(decoders.Get())); } { // Valid 5 decoder pipeline, with an image decoder at the end. auto decoders = pdfium::MakeRetain<CPDF_Array>(); - decoders->AddNew<CPDF_Name>("RunLengthDecode"); - decoders->AddNew<CPDF_Name>("ASCII85Decode"); - decoders->AddNew<CPDF_Name>("FlateDecode"); - decoders->AddNew<CPDF_Name>("LZW"); - decoders->AddNew<CPDF_Name>("DCTDecode"); + decoders->AppendNew<CPDF_Name>("RunLengthDecode"); + decoders->AppendNew<CPDF_Name>("ASCII85Decode"); + decoders->AppendNew<CPDF_Name>("FlateDecode"); + decoders->AppendNew<CPDF_Name>("LZW"); + decoders->AppendNew<CPDF_Name>("DCTDecode"); EXPECT_TRUE(ValidateDecoderPipeline(decoders.Get())); } { // Invalid 1 decoder pipeline due to wrong type. auto decoders = pdfium::MakeRetain<CPDF_Array>(); - decoders->AddNew<CPDF_String>("FlateEncode", false); + decoders->AppendNew<CPDF_String>("FlateEncode", false); EXPECT_FALSE(ValidateDecoderPipeline(decoders.Get())); } { // Invalid 2 decoder pipeline, with 2 image decoders. auto decoders = pdfium::MakeRetain<CPDF_Array>(); - decoders->AddNew<CPDF_Name>("DCTDecode"); - decoders->AddNew<CPDF_Name>("CCITTFaxDecode"); + decoders->AppendNew<CPDF_Name>("DCTDecode"); + decoders->AppendNew<CPDF_Name>("CCITTFaxDecode"); EXPECT_FALSE(ValidateDecoderPipeline(decoders.Get())); } { // Invalid 2 decoder pipeline, with 1 image decoder at the start. auto decoders = pdfium::MakeRetain<CPDF_Array>(); - decoders->AddNew<CPDF_Name>("DCTDecode"); - decoders->AddNew<CPDF_Name>("FlateDecode"); + decoders->AppendNew<CPDF_Name>("DCTDecode"); + decoders->AppendNew<CPDF_Name>("FlateDecode"); EXPECT_FALSE(ValidateDecoderPipeline(decoders.Get())); } { // Invalid 2 decoder pipeline due to wrong type. auto decoders = pdfium::MakeRetain<CPDF_Array>(); - decoders->AddNew<CPDF_String>("AHx", false); - decoders->AddNew<CPDF_Name>("LZWDecode"); + decoders->AppendNew<CPDF_String>("AHx", false); + decoders->AppendNew<CPDF_Name>("LZWDecode"); EXPECT_FALSE(ValidateDecoderPipeline(decoders.Get())); } { // Invalid 5 decoder pipeline. auto decoders = pdfium::MakeRetain<CPDF_Array>(); - decoders->AddNew<CPDF_Name>("FlateDecode"); - decoders->AddNew<CPDF_Name>("FlateDecode"); - decoders->AddNew<CPDF_Name>("DCTDecode"); - decoders->AddNew<CPDF_Name>("FlateDecode"); - decoders->AddNew<CPDF_Name>("FlateDecode"); + decoders->AppendNew<CPDF_Name>("FlateDecode"); + decoders->AppendNew<CPDF_Name>("FlateDecode"); + decoders->AppendNew<CPDF_Name>("DCTDecode"); + decoders->AppendNew<CPDF_Name>("FlateDecode"); + decoders->AppendNew<CPDF_Name>("FlateDecode"); EXPECT_FALSE(ValidateDecoderPipeline(decoders.Get())); } { // Invalid 5 decoder pipeline due to wrong type. auto decoders = pdfium::MakeRetain<CPDF_Array>(); - decoders->AddNew<CPDF_Name>("ASCII85Decode"); - decoders->AddNew<CPDF_Name>("A85"); - decoders->AddNew<CPDF_Name>("RunLengthDecode"); - decoders->AddNew<CPDF_Name>("FlateDecode"); - decoders->AddNew<CPDF_String>("RL", false); + decoders->AppendNew<CPDF_Name>("ASCII85Decode"); + decoders->AppendNew<CPDF_Name>("A85"); + decoders->AppendNew<CPDF_Name>("RunLengthDecode"); + decoders->AppendNew<CPDF_Name>("FlateDecode"); + decoders->AppendNew<CPDF_String>("RL", false); EXPECT_FALSE(ValidateDecoderPipeline(decoders.Get())); } } -TEST(fpdf_parser_decode, A85Decode) { +TEST(ParserDecodeTest, ValidateDecoderPipelineWithIndirectObjects) { + { + // Valid 2 decoder pipeline with indirect objects. + CPDF_IndirectObjectHolder objects_holder; + auto decoder = pdfium::MakeRetain<CPDF_Name>(nullptr, "FlateDecode"); + uint32_t decoder_number = + objects_holder.AddIndirectObject(std::move(decoder)); + + auto decoders = pdfium::MakeRetain<CPDF_Array>(); + decoders->AppendNew<CPDF_Reference>(&objects_holder, decoder_number); + decoders->AppendNew<CPDF_Name>("LZW"); + EXPECT_TRUE(ValidateDecoderPipeline(decoders.Get())); + } + { + // Valid 5 decoder pipeline with indirect objects, with an image decoder at + // the end. + CPDF_IndirectObjectHolder objects_holder; + auto decoder = pdfium::MakeRetain<CPDF_Name>(nullptr, "LZW"); + uint32_t decoder_number = + objects_holder.AddIndirectObject(std::move(decoder)); + + auto decoders = pdfium::MakeRetain<CPDF_Array>(); + decoders->AppendNew<CPDF_Name>("RunLengthDecode"); + decoders->AppendNew<CPDF_Name>("ASCII85Decode"); + decoders->AppendNew<CPDF_Name>("FlateDecode"); + decoders->AppendNew<CPDF_Reference>(&objects_holder, decoder_number); + decoders->AppendNew<CPDF_Name>("DCTDecode"); + EXPECT_TRUE(ValidateDecoderPipeline(decoders.Get())); + } + { + // Invalid 2 decoder pipeline due to wrong type indirect object. + CPDF_IndirectObjectHolder objects_holder; + auto decoder = + pdfium::MakeRetain<CPDF_String>(nullptr, "FlateDecode", false); + uint32_t decoder_number = + objects_holder.AddIndirectObject(std::move(decoder)); + + auto decoders = pdfium::MakeRetain<CPDF_Array>(); + decoders->AppendNew<CPDF_Reference>(&objects_holder, decoder_number); + decoders->AppendNew<CPDF_Name>("LZW"); + EXPECT_FALSE(ValidateDecoderPipeline(decoders.Get())); + } + { + // Invalid 2 decoder pipeline due to invalid indirect object. + CPDF_IndirectObjectHolder objects_holder; + auto decoder = pdfium::MakeRetain<CPDF_Name>(nullptr, "DCTDecode"); + uint32_t decoder_number = + objects_holder.AddIndirectObject(std::move(decoder)); + + auto decoders = pdfium::MakeRetain<CPDF_Array>(); + decoders->AppendNew<CPDF_Reference>(&objects_holder, decoder_number); + decoders->AppendNew<CPDF_Name>("LZW"); + EXPECT_FALSE(ValidateDecoderPipeline(decoders.Get())); + } +} + +// TODO(thestig): Test decoder params. +TEST(ParserDecodeTest, GetDecoderArray) { + { + // Treat no filter as an empty filter array. + auto dict = pdfium::MakeRetain<CPDF_Dictionary>(); + absl::optional<DecoderArray> decoder_array = GetDecoderArray(dict); + ASSERT_TRUE(decoder_array.has_value()); + EXPECT_TRUE(decoder_array.value().empty()); + } + { + // Wrong filter type. + auto dict = pdfium::MakeRetain<CPDF_Dictionary>(); + dict->SetNewFor<CPDF_String>("Filter", "RL", false); + absl::optional<DecoderArray> decoder_array = GetDecoderArray(dict); + EXPECT_FALSE(decoder_array.has_value()); + } + { + // Filter name. + auto dict = pdfium::MakeRetain<CPDF_Dictionary>(); + dict->SetNewFor<CPDF_Name>("Filter", "RL"); + absl::optional<DecoderArray> decoder_array = GetDecoderArray(dict); + ASSERT_TRUE(decoder_array.has_value()); + ASSERT_EQ(1u, decoder_array.value().size()); + EXPECT_EQ("RL", decoder_array.value()[0].first); + } + { + // Empty filter array. + auto dict = pdfium::MakeRetain<CPDF_Dictionary>(); + dict->SetNewFor<CPDF_Array>("Filter"); + absl::optional<DecoderArray> decoder_array = GetDecoderArray(dict); + ASSERT_TRUE(decoder_array.has_value()); + EXPECT_TRUE(decoder_array.value().empty()); + } + { + // Valid 1 element filter array. + auto dict = pdfium::MakeRetain<CPDF_Dictionary>(); + auto filter_array = dict->SetNewFor<CPDF_Array>("Filter"); + filter_array->AppendNew<CPDF_Name>("FooBar"); + absl::optional<DecoderArray> decoder_array = GetDecoderArray(dict); + ASSERT_TRUE(decoder_array.has_value()); + ASSERT_EQ(1u, decoder_array.value().size()); + EXPECT_EQ("FooBar", decoder_array.value()[0].first); + } + { + // Valid 2 element filter array. + auto dict = pdfium::MakeRetain<CPDF_Dictionary>(); + auto filter_array = dict->SetNewFor<CPDF_Array>("Filter"); + filter_array->AppendNew<CPDF_Name>("AHx"); + filter_array->AppendNew<CPDF_Name>("LZWDecode"); + absl::optional<DecoderArray> decoder_array = GetDecoderArray(dict); + ASSERT_TRUE(decoder_array.has_value()); + ASSERT_EQ(2u, decoder_array.value().size()); + EXPECT_EQ("AHx", decoder_array.value()[0].first); + EXPECT_EQ("LZWDecode", decoder_array.value()[1].first); + } + { + // Invalid 2 element filter array. + auto dict = pdfium::MakeRetain<CPDF_Dictionary>(); + auto invalid_filter_array = dict->SetNewFor<CPDF_Array>("Filter"); + invalid_filter_array->AppendNew<CPDF_Name>("DCTDecode"); + invalid_filter_array->AppendNew<CPDF_Name>("CCITTFaxDecode"); + absl::optional<DecoderArray> decoder_array = GetDecoderArray(dict); + EXPECT_FALSE(decoder_array.has_value()); + } +} + +TEST(ParserDecodeTest, A85Decode) { const pdfium::DecodeTestData kTestData[] = { // Empty src string. STR_IN_OUT_CASE("", "", 0), @@ -147,7 +274,76 @@ } } -TEST(fpdf_parser_decode, HexDecode) { +// NOTE: python's zlib.compress() and zlib.decompress() may be useful for +// external validation of the FlateDncode/FlateEecode test cases. +TEST(FPDFParserDecodeEmbedderTest, FlateDecode) { + static const pdfium::DecodeTestData flate_decode_cases[] = { + STR_IN_OUT_CASE("", "", 0), + STR_IN_OUT_CASE("preposterous nonsense", "", 2), + STR_IN_OUT_CASE("\x78\x9c\x03\x00\x00\x00\x00\x01", "", 8), + STR_IN_OUT_CASE("\x78\x9c\x53\x00\x00\x00\x21\x00\x21", " ", 9), + STR_IN_OUT_CASE("\x78\x9c\x33\x34\x32\x06\x00\01\x2d\x00\x97", "123", 11), + STR_IN_OUT_CASE("\x78\x9c\x63\xf8\x0f\x00\x01\x01\x01\x00", "\x00\xff", + 10), + STR_IN_OUT_CASE( + "\x78\x9c\x33\x54\x30\x00\x42\x5d\x43\x05\x23\x4b\x05\x73\x33\x63" + "\x85\xe4\x5c\x2e\x90\x80\xa9\xa9\xa9\x82\xb9\xb1\xa9\x42\x51\x2a" + "\x57\xb8\x42\x1e\x57\x21\x92\xa0\x89\x9e\xb1\xa5\x09\x92\x84\x9e" + "\x85\x81\x81\x25\xd8\x14\x24\x26\xd0\x18\x43\x05\x10\x0c\x72\x57" + "\x80\x30\x8a\xd2\xb9\xf4\xdd\x0d\x14\xd2\x8b\xc1\x46\x99\x59\x1a" + "\x2b\x58\x1a\x9a\x83\x8c\x49\xe3\x0a\x04\x42\x00\x37\x4c\x1b\x42", + "1 0 0 -1 29 763 cm\n0 0 555 735 re\nW n\nq\n0 0 555 734.394 re\n" + "W n\nq\n0.8009 0 0 0.8009 0 0 cm\n1 1 1 RG 1 1 1 rg\n/G0 gs\n" + "0 0 693 917 re\nf\nQ\nQ\n", + 96), + }; + + for (size_t i = 0; i < std::size(flate_decode_cases); ++i) { + const pdfium::DecodeTestData& data = flate_decode_cases[i]; + std::unique_ptr<uint8_t, FxFreeDeleter> buf; + uint32_t buf_size; + EXPECT_EQ(data.processed_size, + FlateDecode({data.input, data.input_size}, &buf, &buf_size)) + << " for case " << i; + ASSERT_TRUE(buf); + EXPECT_EQ(data.expected_size, buf_size) << " for case " << i; + if (data.expected_size != buf_size) + continue; + EXPECT_EQ(0, memcmp(data.expected, buf.get(), data.expected_size)) + << " for case " << i; + } +} + +TEST(ParserDecodeTest, FlateEncode) { + static const pdfium::StrFuncTestData flate_encode_cases[] = { + STR_IN_OUT_CASE("", "\x78\x9c\x03\x00\x00\x00\x00\x01"), + STR_IN_OUT_CASE(" ", "\x78\x9c\x53\x00\x00\x00\x21\x00\x21"), + STR_IN_OUT_CASE("123", "\x78\x9c\x33\x34\x32\x06\x00\01\x2d\x00\x97"), + STR_IN_OUT_CASE("\x00\xff", "\x78\x9c\x63\xf8\x0f\x00\x01\x01\x01\x00"), + STR_IN_OUT_CASE( + "1 0 0 -1 29 763 cm\n0 0 555 735 re\nW n\nq\n0 0 555 734.394 re\n" + "W n\nq\n0.8009 0 0 0.8009 0 0 cm\n1 1 1 RG 1 1 1 rg\n/G0 gs\n" + "0 0 693 917 re\nf\nQ\nQ\n", + "\x78\x9c\x33\x54\x30\x00\x42\x5d\x43\x05\x23\x4b\x05\x73\x33\x63" + "\x85\xe4\x5c\x2e\x90\x80\xa9\xa9\xa9\x82\xb9\xb1\xa9\x42\x51\x2a" + "\x57\xb8\x42\x1e\x57\x21\x92\xa0\x89\x9e\xb1\xa5\x09\x92\x84\x9e" + "\x85\x81\x81\x25\xd8\x14\x24\x26\xd0\x18\x43\x05\x10\x0c\x72\x57" + "\x80\x30\x8a\xd2\xb9\xf4\xdd\x0d\x14\xd2\x8b\xc1\x46\x99\x59\x1a" + "\x2b\x58\x1a\x9a\x83\x8c\x49\xe3\x0a\x04\x42\x00\x37\x4c\x1b\x42"), + }; + + for (size_t i = 0; i < std::size(flate_encode_cases); ++i) { + const pdfium::StrFuncTestData& data = flate_encode_cases[i]; + DataVector<uint8_t> result = FlateEncode({data.input, data.input_size}); + EXPECT_EQ(data.expected_size, result.size()) << " for case " << i; + if (data.expected_size != result.size()) + continue; + EXPECT_EQ(0, memcmp(data.expected, result.data(), data.expected_size)) + << " for case " << i; + } +} + +TEST(ParserDecodeTest, HexDecode) { const pdfium::DecodeTestData kTestData[] = { // Empty src string. STR_IN_OUT_CASE("", "", 0), @@ -182,7 +378,7 @@ } } -TEST(fpdf_parser_decode, DecodeText) { +TEST(ParserDecodeTest, DecodeText) { const struct DecodeTestData { const char* input; size_t input_length; @@ -231,7 +427,7 @@ } } -TEST(fpdf_parser_decode, EncodeText) { +TEST(ParserDecodeTest, EncodeText) { const struct EncodeTestData { const wchar_t* input; const char* expected_output;
diff --git a/core/fpdfapi/parser/fpdf_parser_utility.cpp b/core/fpdfapi/parser/fpdf_parser_utility.cpp index af58e8d..950753e 100644 --- a/core/fpdfapi/parser/fpdf_parser_utility.cpp +++ b/core/fpdfapi/parser/fpdf_parser_utility.cpp
@@ -1,4 +1,4 @@ -// Copyright 2014 PDFium Authors. All rights reserved. +// Copyright 2014 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -6,10 +6,12 @@ #include "core/fpdfapi/parser/fpdf_parser_utility.h" +#include <ostream> +#include <utility> + #include "core/fpdfapi/parser/cpdf_array.h" #include "core/fpdfapi/parser/cpdf_boolean.h" #include "core/fpdfapi/parser/cpdf_dictionary.h" -#include "core/fpdfapi/parser/cpdf_name.h" #include "core/fpdfapi/parser/cpdf_number.h" #include "core/fpdfapi/parser/cpdf_reference.h" #include "core/fpdfapi/parser/cpdf_stream.h" @@ -18,7 +20,8 @@ #include "core/fpdfapi/parser/fpdf_parser_decode.h" #include "core/fxcrt/fx_extension.h" #include "core/fxcrt/fx_stream.h" -#include "third_party/base/logging.h" +#include "third_party/base/check.h" +#include "third_party/base/notreached.h" // Indexed by 8-bit character code, contains either: // 'W' - for whitespace: NUL, TAB, CR, LF, FF, SPACE, 0x80, 0xff @@ -72,29 +75,21 @@ 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'R', 'W'}; -Optional<FX_FILESIZE> GetHeaderOffset( +absl::optional<FX_FILESIZE> GetHeaderOffset( const RetainPtr<IFX_SeekableReadStream>& pFile) { static constexpr size_t kBufSize = 4; uint8_t buf[kBufSize]; for (FX_FILESIZE offset = 0; offset <= 1024; ++offset) { - if (!pFile->ReadBlockAtOffset(buf, offset, kBufSize)) - return {}; + if (!pFile->ReadBlockAtOffset(buf, offset)) + return absl::nullopt; if (memcmp(buf, "%PDF", 4) == 0) return offset; } - return {}; -} - -int32_t GetDirectInteger(const CPDF_Dictionary* pDict, const ByteString& key) { - const CPDF_Number* pObj = ToNumber(pDict->GetObjectFor(key)); - return pObj ? pObj->GetInteger() : 0; + return absl::nullopt; } ByteString PDF_NameDecode(ByteStringView orig) { - if (!orig.Contains('#')) - return ByteString(orig); - size_t src_size = orig.GetLength(); size_t out_index = 0; ByteString result; @@ -155,30 +150,29 @@ std::vector<float> ReadArrayElementsToVector(const CPDF_Array* pArray, size_t nCount) { - ASSERT(pArray); - ASSERT(pArray->size() >= nCount); + DCHECK(pArray); + DCHECK(pArray->size() >= nCount); std::vector<float> ret(nCount); for (size_t i = 0; i < nCount; ++i) - ret[i] = pArray->GetNumberAt(i); + ret[i] = pArray->GetFloatAt(i); return ret; } -bool ValidateDictType(const CPDF_Dictionary* dict, const ByteString& type) { - ASSERT(dict); - ASSERT(!type.IsEmpty()); - const CPDF_Name* name_obj = ToName(dict->GetObjectFor("Type")); - return name_obj && name_obj->GetString() == type; +bool ValidateDictType(const CPDF_Dictionary* dict, ByteStringView type) { + DCHECK(!type.IsEmpty()); + return dict && dict->GetNameFor("Type") == type; } bool ValidateDictAllResourcesOfType(const CPDF_Dictionary* dict, - const ByteString& type) { + ByteStringView type) { if (!dict) return false; CPDF_DictionaryLocker locker(dict); for (const auto& it : locker) { - const CPDF_Dictionary* entry = ToDictionary(it.second.Get()->GetDirect()); - if (!entry || !ValidateDictType(entry, type)) + RetainPtr<const CPDF_Dictionary> entry = + ToDictionary(it.second->GetDirect()); + if (!ValidateDictType(entry.Get(), type)) return false; } return true; @@ -188,6 +182,12 @@ return ValidateDictAllResourcesOfType(dict, "Font"); } +bool ValidateDictOptionalType(const CPDF_Dictionary* dict, + ByteStringView type) { + DCHECK(!type.IsEmpty()); + return dict && (!dict->KeyExist("Type") || dict->GetNameFor("Type") == type); +} + std::ostream& operator<<(std::ostream& buf, const CPDF_Object* pObj) { if (!pObj) { buf << " null"; @@ -202,7 +202,7 @@ buf << " " << pObj->GetString(); break; case CPDF_Object::kString: - buf << PDF_EncodeString(pObj->GetString(), pObj->AsString()->IsHex()); + buf << pObj->AsString()->EncodeString(); break; case CPDF_Object::kName: { ByteString str = pObj->GetString(); @@ -217,11 +217,11 @@ const CPDF_Array* p = pObj->AsArray(); buf << "["; for (size_t i = 0; i < p->size(); i++) { - const CPDF_Object* pElement = p->GetObjectAt(i); - if (pElement && !pElement->IsInline()) { + RetainPtr<const CPDF_Object> pElement = p->GetObjectAt(i); + if (!pElement->IsInline()) { buf << " " << pElement->GetObjNum() << " 0 R"; } else { - buf << pElement; + buf << pElement.Get(); } } buf << "]"; @@ -232,9 +232,9 @@ buf << "<<"; for (const auto& it : locker) { const ByteString& key = it.first; - CPDF_Object* pValue = it.second.Get(); + const RetainPtr<CPDF_Object>& pValue = it.second; buf << "/" << PDF_NameEncode(key); - if (pValue && !pValue->IsInline()) { + if (!pValue->IsInline()) { buf << " " << pValue->GetObjNum() << " 0 R "; } else { buf << pValue; @@ -244,12 +244,12 @@ break; } case CPDF_Object::kStream: { - const CPDF_Stream* p = pObj->AsStream(); - buf << p->GetDict() << "stream\r\n"; - auto pAcc = pdfium::MakeRetain<CPDF_StreamAcc>(p); + RetainPtr<const CPDF_Stream> p(pObj->AsStream()); + buf << p->GetDict().Get() << "stream\r\n"; + auto pAcc = pdfium::MakeRetain<CPDF_StreamAcc>(std::move(p)); pAcc->LoadAllDataRaw(); - buf.write(reinterpret_cast<const char*>(pAcc->GetData()), - pAcc->GetSize()); + pdfium::span<const uint8_t> span = pAcc->GetSpan(); + buf.write(reinterpret_cast<const char*>(span.data()), span.size()); buf << "\r\nendstream"; break; }
diff --git a/core/fpdfapi/parser/fpdf_parser_utility.h b/core/fpdfapi/parser/fpdf_parser_utility.h index 75f4076..259495e 100644 --- a/core/fpdfapi/parser/fpdf_parser_utility.h +++ b/core/fpdfapi/parser/fpdf_parser_utility.h
@@ -1,4 +1,4 @@ -// Copyright 2016 PDFium Authors. All rights reserved. +// Copyright 2016 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -7,12 +7,12 @@ #ifndef CORE_FPDFAPI_PARSER_FPDF_PARSER_UTILITY_H_ #define CORE_FPDFAPI_PARSER_FPDF_PARSER_UTILITY_H_ -#include <ostream> +#include <iosfwd> #include <vector> -#include "core/fxcrt/fx_string.h" +#include "core/fxcrt/bytestring.h" #include "core/fxcrt/retain_ptr.h" -#include "third_party/base/optional.h" +#include "third_party/abseil-cpp/absl/types/optional.h" class CPDF_Array; class CPDF_Dictionary; @@ -42,11 +42,9 @@ // On success, return a positive offset value to the PDF header. If the header // cannot be found, or if there is an error reading from |pFile|, then return // nullopt. -Optional<FX_FILESIZE> GetHeaderOffset( +absl::optional<FX_FILESIZE> GetHeaderOffset( const RetainPtr<IFX_SeekableReadStream>& pFile); -int32_t GetDirectInteger(const CPDF_Dictionary* pDict, const ByteString& key); - ByteString PDF_NameDecode(ByteStringView orig); ByteString PDF_NameEncode(const ByteString& orig); @@ -55,17 +53,21 @@ std::vector<float> ReadArrayElementsToVector(const CPDF_Array* pArray, size_t nCount); -// Returns true if |dict| has a /Type name entry that matches |type|. -bool ValidateDictType(const CPDF_Dictionary* dict, const ByteString& type); +// Returns true if |dict| is non-null and has a /Type name entry that matches +// |type|. +bool ValidateDictType(const CPDF_Dictionary* dict, ByteStringView type); // Returns true if |dict| is non-null and all entries in |dict| are dictionaries // of |type|. bool ValidateDictAllResourcesOfType(const CPDF_Dictionary* dict, - const ByteString& type); + ByteStringView type); // Shorthand for ValidateDictAllResourcesOfType(dict, "Font"). bool ValidateFontResourceDict(const CPDF_Dictionary* dict); +// Like ValidateDictType(), but /Type can also not exist. +bool ValidateDictOptionalType(const CPDF_Dictionary* dict, ByteStringView type); + std::ostream& operator<<(std::ostream& buf, const CPDF_Object* pObj); #endif // CORE_FPDFAPI_PARSER_FPDF_PARSER_UTILITY_H_
diff --git a/core/fpdfapi/parser/fpdf_parser_utility_unittest.cpp b/core/fpdfapi/parser/fpdf_parser_utility_unittest.cpp index 098c3bd..898ab62 100644 --- a/core/fpdfapi/parser/fpdf_parser_utility_unittest.cpp +++ b/core/fpdfapi/parser/fpdf_parser_utility_unittest.cpp
@@ -1,20 +1,21 @@ -// Copyright 2018 PDFium Authors. All rights reserved. +// Copyright 2018 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "core/fpdfapi/parser/fpdf_parser_utility.h" -#include "core/fpdfapi/page/cpdf_docpagedata.h" +#include <memory> + #include "core/fpdfapi/page/cpdf_pagemodule.h" #include "core/fpdfapi/parser/cpdf_dictionary.h" #include "core/fpdfapi/parser/cpdf_document.h" #include "core/fpdfapi/parser/cpdf_name.h" #include "core/fpdfapi/parser/cpdf_reference.h" #include "core/fpdfapi/parser/cpdf_string.h" -#include "core/fpdfapi/render/cpdf_docrenderdata.h" +#include "core/fpdfapi/parser/cpdf_test_document.h" #include "testing/gtest/include/gtest/gtest.h" -TEST(fpdf_parser_utility, PDF_NameDecode) { +TEST(ParserUtilityTest, NameDecode) { EXPECT_EQ("", PDF_NameDecode("")); EXPECT_EQ("A", PDF_NameDecode("A")); EXPECT_EQ("#", PDF_NameDecode("#")); @@ -23,7 +24,7 @@ EXPECT_EQ("A1", PDF_NameDecode("#411")); } -TEST(fpdf_parser_utility, PDF_NameEncode) { +TEST(ParserUtilityTest, NameEncode) { EXPECT_EQ("", PDF_NameEncode("")); EXPECT_EQ("A", PDF_NameEncode("A")); EXPECT_EQ("#23", PDF_NameEncode("#")); @@ -33,7 +34,7 @@ EXPECT_EQ("f#C2#A5", PDF_NameEncode("f\xc2\xa5")); } -TEST(fpdf_parser_utility, ValidateDictType) { +TEST(ParserUtilityTest, ValidateDictType) { auto dict = pdfium::MakeRetain<CPDF_Dictionary>(); // No type. @@ -51,7 +52,7 @@ EXPECT_FALSE(ValidateDictType(dict.Get(), "bar")); } -TEST(fpdf_parser_utility, ValidateDictAllResourcesOfType) { +TEST(ParserUtilityTest, ValidateDictAllResourcesOfType) { CPDF_PageModule::Create(); { @@ -67,7 +68,7 @@ EXPECT_FALSE(ValidateDictAllResourcesOfType(nullptr, "bar")); // Add two correct dictionary entries and one string entry. - CPDF_Dictionary* new_dict = dict->SetNewFor<CPDF_Dictionary>("f1"); + auto new_dict = dict->SetNewFor<CPDF_Dictionary>("f1"); new_dict->SetNewFor<CPDF_Name>("Type", "foo"); new_dict = dict->SetNewFor<CPDF_Dictionary>("f2"); new_dict->SetNewFor<CPDF_Name>("Type", "foo"); @@ -89,14 +90,11 @@ { // Indirect dictionary. - auto doc = pdfium::MakeUnique<CPDF_Document>( - pdfium::MakeUnique<CPDF_DocRenderData>(), - pdfium::MakeUnique<CPDF_DocPageData>()); - + auto doc = std::make_unique<CPDF_TestDocument>(); auto dict = doc->New<CPDF_Dictionary>(); // Add a correct dictionary entry. - CPDF_Dictionary* new_dict = doc->NewIndirect<CPDF_Dictionary>(); + auto new_dict = doc->NewIndirect<CPDF_Dictionary>(); new_dict->SetNewFor<CPDF_Name>("Type", "foo"); dict->SetNewFor<CPDF_Reference>("f1", doc.get(), new_dict->GetObjNum()); @@ -106,3 +104,21 @@ CPDF_PageModule::Destroy(); } + +TEST(ParserUtilityTest, ValidateDictOptionalType) { + auto dict = pdfium::MakeRetain<CPDF_Dictionary>(); + + // No type is ok. + EXPECT_TRUE(ValidateDictOptionalType(dict.Get(), "foo")); + EXPECT_TRUE(ValidateDictOptionalType(dict.Get(), "bar")); + + // Add the wrong object type. + dict->SetNewFor<CPDF_String>("Type", L"foo"); + EXPECT_FALSE(ValidateDictOptionalType(dict.Get(), "foo")); + EXPECT_FALSE(ValidateDictOptionalType(dict.Get(), "bar")); + + // Add the correct object type. + dict->SetNewFor<CPDF_Name>("Type", "foo"); + EXPECT_TRUE(ValidateDictOptionalType(dict.Get(), "foo")); + EXPECT_FALSE(ValidateDictOptionalType(dict.Get(), "bar")); +}
diff --git a/core/fpdfapi/parser/object_tree_traversal_util.cpp b/core/fpdfapi/parser/object_tree_traversal_util.cpp new file mode 100644 index 0000000..e1a0d52 --- /dev/null +++ b/core/fpdfapi/parser/object_tree_traversal_util.cpp
@@ -0,0 +1,221 @@ +// Copyright 2023 The PDFium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "core/fpdfapi/parser/object_tree_traversal_util.h" + +#include <stdint.h> + +#include <map> +#include <queue> +#include <set> +#include <utility> +#include <vector> + +#include "core/fpdfapi/parser/cpdf_array.h" +#include "core/fpdfapi/parser/cpdf_dictionary.h" +#include "core/fpdfapi/parser/cpdf_document.h" +#include "core/fpdfapi/parser/cpdf_reference.h" +#include "core/fpdfapi/parser/cpdf_stream.h" +#include "third_party/base/check.h" +#include "third_party/base/containers/contains.h" + +namespace { + +class ObjectTreeTraverser { + public: + explicit ObjectTreeTraverser(const CPDF_Document* document) + : document_(document) { + const CPDF_Parser* parser = document_->GetParser(); + const CPDF_Dictionary* trailer = parser ? parser->GetTrailer() : nullptr; + const CPDF_Dictionary* root = trailer ? trailer : document_->GetRoot(); + const uint32_t root_object_number = + trailer ? parser->GetTrailerObjectNumber() : root->GetObjNum(); + // If `root` is a trailer, then it may not have an object number, as many + // trailers are inlined. + if (root_object_number) { + referenced_objects_[root_object_number] = 1; + object_number_map_[root] = root_object_number; + } + + object_queue_.push(pdfium::WrapRetain(root)); + seen_objects_.insert(root); + } + ~ObjectTreeTraverser() = default; + + void Traverse() { CalculateReferenceCounts(GetReferenceEntries()); } + + const std::map<uint32_t, int>& referenced_objects() { + return referenced_objects_; + } + + private: + struct ReferenceEntry { + uint32_t ref_object_number; + uint32_t referenced_object_number; + }; + + std::vector<ReferenceEntry> GetReferenceEntries() { + std::vector<ReferenceEntry> reference_entries; + while (!object_queue_.empty()) { + RetainPtr<const CPDF_Object> current_object = object_queue_.front(); + object_queue_.pop(); + + switch (current_object->GetType()) { + case CPDF_Object::kArray: { + CPDF_ArrayLocker locker(current_object->AsArray()); + for (const auto& it : locker) { + PushNewObject(current_object, it); + } + break; + } + case CPDF_Object::kDictionary: { + CPDF_DictionaryLocker locker(current_object->AsDictionary()); + for (const auto& it : locker) { + PushNewObject(current_object, it.second); + } + break; + } + case CPDF_Object::kReference: { + const CPDF_Reference* ref_object = current_object->AsReference(); + const uint32_t ref_object_number = GetObjectNumber(ref_object); + const uint32_t referenced_object_number = ref_object->GetRefObjNum(); + CHECK(referenced_object_number); + + RetainPtr<const CPDF_Object> referenced_object; + if (ref_object->HasIndirectObjectHolder()) { + // Calling GetIndirectObject() does not work for normal references. + referenced_object = ref_object->GetDirect(); + } else { + // Calling GetDirect() does not work for references from trailers. + referenced_object = + document_->GetIndirectObject(referenced_object_number); + } + // Unlike the other object types, CPDF_Reference can point at nullptr. + if (referenced_object) { + reference_entries.push_back( + {ref_object_number, referenced_object_number}); + PushNewObject(ref_object, referenced_object); + } + break; + } + case CPDF_Object::kStream: { + RetainPtr<const CPDF_Dictionary> dict = + current_object->AsStream()->GetDict(); + CHECK(dict->IsInline()); // i.e. No object number. + CPDF_DictionaryLocker locker(dict); + for (const auto& it : locker) { + PushNewObject(current_object, it.second); + } + break; + } + default: { + break; + } + } + } + return reference_entries; + } + + void CalculateReferenceCounts( + const std::vector<ReferenceEntry>& reference_entries) { + // Tracks PDF objects that referenced other PDF objects, identified by their + // object numbers. Never 0. + std::set<uint32_t> seen_ref_objects; + + for (const ReferenceEntry& entry : reference_entries) { + // Make sure this is not a self-reference. + if (entry.referenced_object_number == entry.ref_object_number) { + continue; + } + + // Make sure this is not a circular reference. + if (pdfium::Contains(seen_ref_objects, entry.ref_object_number) && + pdfium::Contains(seen_ref_objects, entry.referenced_object_number)) { + continue; + } + + ++referenced_objects_[entry.referenced_object_number]; + if (entry.ref_object_number) { + seen_ref_objects.insert(entry.ref_object_number); + } + } + } + + void PushNewObject(const CPDF_Object* parent_object, + RetainPtr<const CPDF_Object> child_object) { + CHECK(parent_object); + CHECK(child_object); + const bool inserted = seen_objects_.insert(child_object).second; + if (!inserted) { + return; + } + const uint32_t child_object_number = child_object->GetObjNum(); + if (child_object_number) { + object_number_map_[child_object] = child_object_number; + } else { + // This search can fail for inlined trailers. + auto it = object_number_map_.find(parent_object); + if (it != object_number_map_.end()) { + object_number_map_[child_object] = it->second; + } + } + object_queue_.push(std::move(child_object)); + } + + // Returns 0 if not found. + uint32_t GetObjectNumber(const CPDF_Object* object) const { + auto it = object_number_map_.find(object); + return it != object_number_map_.end() ? it->second : 0; + } + + const CPDF_Document* const document_; + + // Queue of objects to traverse. + // - Pointers in the queue are non-null. + // - The same pointer never enters the queue twice. + std::queue<RetainPtr<const CPDF_Object>> object_queue_; + + // Map of objects to "top-level" object numbers. For inline objects, this is + // the ancestor object with an object number. The keys are non-null and the + // values are never 0. + // This is used to prevent self-references, as a single PDF object, with + // inlined objects, is represented by multiple CPDF_Objects. + std::map<const CPDF_Object*, uint32_t> object_number_map_; + + // Tracks traversed objects to prevent duplicates from getting into + // `object_queue_` and `object_number_map_`. + std::set<const CPDF_Object*> seen_objects_; + + // Tracks which PDF objects are referenced. + // Key: object number + // Value: number of times referenced + std::map<uint32_t, int> referenced_objects_; +}; + +} // namespace + +std::set<uint32_t> GetObjectsWithReferences(const CPDF_Document* document) { + ObjectTreeTraverser traverser(document); + traverser.Traverse(); + + std::set<uint32_t> results; + for (const auto& it : traverser.referenced_objects()) { + results.insert(it.first); + } + return results; +} + +std::set<uint32_t> GetObjectsWithMultipleReferences( + const CPDF_Document* document) { + ObjectTreeTraverser traverser(document); + traverser.Traverse(); + + std::set<uint32_t> results; + for (const auto& it : traverser.referenced_objects()) { + if (it.second > 1) { + results.insert(it.first); + } + } + return results; +}
diff --git a/core/fpdfapi/parser/object_tree_traversal_util.h b/core/fpdfapi/parser/object_tree_traversal_util.h new file mode 100644 index 0000000..e9db96d --- /dev/null +++ b/core/fpdfapi/parser/object_tree_traversal_util.h
@@ -0,0 +1,46 @@ +// Copyright 2023 The PDFium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CORE_FPDFAPI_PARSER_OBJECT_TREE_TRAVERSAL_UTIL_H_ +#define CORE_FPDFAPI_PARSER_OBJECT_TREE_TRAVERSAL_UTIL_H_ + +#include <stdint.h> + +#include <set> + +class CPDF_Document; + +// Traverses `document` starting with its trailer, if it has one, or starting at +// the catalog, which always exists. The trailer should have a reference to the +// catalog. The traversal avoids cycles. +// Returns all the PDF objects (not CPDF_Objects) the traversal reached as a set +// of object numbers. +std::set<uint32_t> GetObjectsWithReferences(const CPDF_Document* document); + +// Same as GetObjectsWithReferences(), but only returns the objects with +// multiple references. References that would create a cycle are ignored. +// +// In this example, where (A) is the root node: +// +// A -> B +// A -> C +// B -> D +// C -> D +// +// GetObjectsWithMultipleReferences() returns {D}, since both (B) and (C) +// references to (D), and there are no cycles. +// +// In this example, where (A) is the root node: +// +// A -> B +// B -> C +// C -> B +// +// GetObjectsWithMultipleReferences() returns {}, even though both (A) and (C) +// references (B). Since (B) -> (C) -> (B) creates a cycle, the (C) -> (B) +// reference does not count. +std::set<uint32_t> GetObjectsWithMultipleReferences( + const CPDF_Document* document); + +#endif // CORE_FPDFAPI_PARSER_OBJECT_TREE_TRAVERSAL_UTIL_H_
diff --git a/core/fpdfapi/parser/object_tree_traversal_util_embeddertest.cpp b/core/fpdfapi/parser/object_tree_traversal_util_embeddertest.cpp new file mode 100644 index 0000000..c90c77e --- /dev/null +++ b/core/fpdfapi/parser/object_tree_traversal_util_embeddertest.cpp
@@ -0,0 +1,96 @@ +// Copyright 2023 The PDFium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "core/fpdfapi/parser/object_tree_traversal_util.h" + +#include <stdint.h> + +#include <set> + +#include "core/fpdfapi/parser/cpdf_document.h" +#include "testing/embedder_test.h" +#include "testing/gmock/include/gmock/gmock.h" +#include "testing/gtest/include/gtest/gtest.h" + +using testing::UnorderedElementsAreArray; +using ObjectTreeTraversalUtilEmbedderTest = EmbedderTest; + +namespace { + +CPDF_Document* GetCPDFDocument(FPDF_DOCUMENT document) { + // This is cheating slightly to avoid a layering violation, since this file + // cannot include fpdfsdk/cpdfsdk_helpers.h to get access to + // CPDFDocumentFromFPDFDocument(). + return reinterpret_cast<CPDF_Document*>((document)); +} + +} // namespace + +TEST_F(ObjectTreeTraversalUtilEmbedderTest, GetObjectsWithReferencesBasic) { + ASSERT_TRUE(OpenDocument("hello_world.pdf")); + CPDF_Document* doc = GetCPDFDocument(document()); + std::set<uint32_t> referenced_objects = GetObjectsWithReferences(doc); + EXPECT_THAT(referenced_objects, + UnorderedElementsAreArray({1, 2, 3, 4, 5, 6})); +} + +TEST_F(ObjectTreeTraversalUtilEmbedderTest, GetObjectsWithReferencesNewDoc) { + ScopedFPDFDocument new_doc(FPDF_CreateNewDocument()); + CPDF_Document* doc = GetCPDFDocument(new_doc.get()); + std::set<uint32_t> referenced_objects = GetObjectsWithReferences(doc); + // Empty documents have a catalog and an empty pages object. + EXPECT_THAT(referenced_objects, UnorderedElementsAreArray({1, 2})); +} + +TEST_F(ObjectTreeTraversalUtilEmbedderTest, + GetObjectsWithReferencesCircularRefs) { + ASSERT_TRUE(OpenDocument("circular_viewer_ref.pdf")); + CPDF_Document* doc = GetCPDFDocument(document()); + std::set<uint32_t> referenced_objects = GetObjectsWithReferences(doc); + // The trailer points at a catalog, and the catalog only references itself. + EXPECT_THAT(referenced_objects, UnorderedElementsAreArray({1})); +} + +TEST_F(ObjectTreeTraversalUtilEmbedderTest, + GetObjectsWithReferencesCrossRefStream) { + ASSERT_TRUE(OpenDocument("bug_1399.pdf")); + CPDF_Document* doc = GetCPDFDocument(document()); + std::set<uint32_t> referenced_objects = GetObjectsWithReferences(doc); + // The trailer is the dictionary inside /XRef object 16 0. Note that it + // references object 3 0, but the rest of the document does not. + EXPECT_THAT(referenced_objects, + UnorderedElementsAreArray({1, 2, 3, 4, 5, 12, 13, 14, 16})); +} + +TEST_F(ObjectTreeTraversalUtilEmbedderTest, + GetObjectsWithMultipleReferencesBasic) { + ASSERT_TRUE(OpenDocument("hello_world.pdf")); + CPDF_Document* doc = GetCPDFDocument(document()); + std::set<uint32_t> referenced_objects = GetObjectsWithMultipleReferences(doc); + EXPECT_TRUE(referenced_objects.empty()); +} + +TEST_F(ObjectTreeTraversalUtilEmbedderTest, + GetObjectsWithMultipleReferencesNewDoc) { + ScopedFPDFDocument new_doc(FPDF_CreateNewDocument()); + CPDF_Document* doc = GetCPDFDocument(new_doc.get()); + std::set<uint32_t> referenced_objects = GetObjectsWithMultipleReferences(doc); + EXPECT_TRUE(referenced_objects.empty()); +} + +TEST_F(ObjectTreeTraversalUtilEmbedderTest, + GetObjectsWithMultipleReferencesCircularRefs) { + ASSERT_TRUE(OpenDocument("circular_viewer_ref.pdf")); + CPDF_Document* doc = GetCPDFDocument(document()); + std::set<uint32_t> referenced_objects = GetObjectsWithMultipleReferences(doc); + EXPECT_TRUE(referenced_objects.empty()); +} + +TEST_F(ObjectTreeTraversalUtilEmbedderTest, + GetObjectsWithMultipleReferencesSharedObjects) { + ASSERT_TRUE(OpenDocument("hello_world_2_pages.pdf")); + CPDF_Document* doc = GetCPDFDocument(document()); + std::set<uint32_t> referenced_objects = GetObjectsWithMultipleReferences(doc); + EXPECT_THAT(referenced_objects, UnorderedElementsAreArray({5, 6, 7})); +}
diff --git a/core/fpdfapi/render/Android.bp b/core/fpdfapi/render/Android.bp index 79b0db6..cd2b82d 100644 --- a/core/fpdfapi/render/Android.bp +++ b/core/fpdfapi/render/Android.bp
@@ -13,11 +13,8 @@ visibility: ["//external/pdfium:__subpackages__"], - header_libs: [ - "libpdfium-constants", - ], - static_libs: [ + "libpdfium-constants", "libpdfium-fxcodec", "libpdfium-fxcrt", "libpdfium-fxge",
diff --git a/core/fpdfapi/render/BUILD.gn b/core/fpdfapi/render/BUILD.gn index ddce77a..bb76ef8 100644 --- a/core/fpdfapi/render/BUILD.gn +++ b/core/fpdfapi/render/BUILD.gn
@@ -1,4 +1,4 @@ -# Copyright 2018 The PDFium Authors. All rights reserved. +# Copyright 2018 The PDFium Authors # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. @@ -7,20 +7,14 @@ source_set("render") { sources = [ - "cpdf_charposlist.cpp", - "cpdf_charposlist.h", + "charposlist.cpp", + "charposlist.h", "cpdf_devicebuffer.cpp", "cpdf_devicebuffer.h", "cpdf_docrenderdata.cpp", "cpdf_docrenderdata.h", - "cpdf_imagecacheentry.cpp", - "cpdf_imagecacheentry.h", - "cpdf_imageloader.cpp", - "cpdf_imageloader.h", "cpdf_imagerenderer.cpp", "cpdf_imagerenderer.h", - "cpdf_pagerendercache.cpp", - "cpdf_pagerendercache.h", "cpdf_pagerendercontext.cpp", "cpdf_pagerendercontext.h", "cpdf_progressiverenderer.cpp", @@ -33,6 +27,8 @@ "cpdf_rendershading.h", "cpdf_renderstatus.cpp", "cpdf_renderstatus.h", + "cpdf_rendertiling.cpp", + "cpdf_rendertiling.h", "cpdf_scaledrenderbuffer.cpp", "cpdf_scaledrenderbuffer.h", "cpdf_textrenderer.cpp", @@ -42,7 +38,10 @@ "cpdf_type3glyphmap.cpp", "cpdf_type3glyphmap.h", ] - configs += [ "../../../:pdfium_core_config" ] + configs += [ + "../../../:pdfium_strict_config", + "../../../:pdfium_noshorten_config", + ] deps = [ "../../../constants", "../../fxcodec", @@ -52,13 +51,13 @@ "../page", "../parser", ] + visibility = [ "../../../*" ] if (is_win) { sources += [ "cpdf_windowsrenderdevice.cpp", "cpdf_windowsrenderdevice.h", ] } - visibility = [ "../../../*" ] } pdfium_unittest_source_set("unittests") { @@ -76,5 +75,6 @@ "fpdf_progressive_render_embeddertest.cpp", "fpdf_render_pattern_embeddertest.cpp", ] + deps = [ "../../fxge" ] pdfium_root_dir = "../../../" }
diff --git a/core/fpdfapi/render/charposlist.cpp b/core/fpdfapi/render/charposlist.cpp new file mode 100644 index 0000000..aba0ada --- /dev/null +++ b/core/fpdfapi/render/charposlist.cpp
@@ -0,0 +1,196 @@ +// Copyright 2016 The PDFium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com + +#include "core/fpdfapi/render/charposlist.h" + +#include "build/build_config.h" +#include "core/fpdfapi/font/cpdf_cidfont.h" +#include "core/fpdfapi/font/cpdf_font.h" +#include "core/fpdfapi/parser/cpdf_stream.h" +#include "core/fxge/cfx_fontmapper.h" +#include "core/fxge/cfx_substfont.h" +#include "core/fxge/text_char_pos.h" + +namespace { + +bool ShouldUseExistingFont(const CPDF_Font* font, + uint32_t glyph_id, + bool has_to_unicode) { + // Check for invalid glyph ID. + if (glyph_id == static_cast<uint32_t>(-1)) + return false; + + if (!font->IsTrueTypeFont()) + return true; + + // For TrueType fonts, a glyph ID of 0 may be invalid. + // + // When a "ToUnicode" entry exists in the font dictionary, it indicates + // a "ToUnicode" mapping file is used to convert from CIDs (which + // begins at decimal 0) to Unicode code. (See ToUnicode Mapping File + // Tutorial - Adobe + // https://www.adobe.com/content/dam/acom/en/devnet/acrobat/pdfs/5411.ToUnicode.pdf + // and + // https://www.freetype.org/freetype2/docs/tutorial/step1.html#section-6) + return glyph_id != 0 || has_to_unicode; +} + +// The following is not a perfect solution and can be further improved. +// For example, if `subst_font` is "Book" and the `base_font_name` is "Bookman", +// this function will return "true" even though the actual font "Bookman" +// is not loaded. +// An exact string match is not possible here, because `subst_font_name` +// will be the same value for different postscript names. +// For example: "Times New Roman" as `subst_font_name` for all of these +// `base_font_name` values: "TimesNewRoman,Bold", "TimesNewRomanPS-Bold", +// "TimesNewRomanBold" and "TimesNewRoman-Bold". +bool IsActualFontLoaded(const CFX_SubstFont* subst_font, + const ByteString& base_font_name) { + // Skip if we loaded the actual font. + // example: TimesNewRoman,Bold -> Times New Roman + ByteString subst_font_name = subst_font->m_Family; + subst_font_name.Remove(' '); + subst_font_name.MakeLower(); + + absl::optional<size_t> find = + base_font_name.Find(subst_font_name.AsStringView()); + return find.has_value() && find.value() == 0; +} + +bool ApplyGlyphSpacingHeuristic(const CPDF_Font* font, + const CFX_Font* current_font, + bool is_vertical_writing) { + if (is_vertical_writing || font->IsEmbedded() || !font->HasFontWidths()) { + return false; + } + + // Skip if we loaded a standard alternate font. + // example: Helvetica -> Arial + ByteString base_font_name = font->GetBaseFontName(); + base_font_name.MakeLower(); + + auto standard_font_name = + CFX_FontMapper::GetStandardFontName(&base_font_name); + if (standard_font_name.has_value()) { + return false; + } + + CFX_SubstFont* subst_font = current_font->GetSubstFont(); + if (subst_font->IsBuiltInGenericFont()) { + return false; + } + + return !IsActualFontLoaded(subst_font, base_font_name); +} + +} // namespace + +std::vector<TextCharPos> GetCharPosList(pdfium::span<const uint32_t> char_codes, + pdfium::span<const float> char_pos, + CPDF_Font* font, + float font_size) { + std::vector<TextCharPos> results; + results.reserve(char_codes.size()); + + CPDF_CIDFont* cid_font = font->AsCIDFont(); + bool is_vertical_writing = cid_font && cid_font->IsVertWriting(); + bool has_to_unicode = !!font->GetFontDict()->GetStreamFor("ToUnicode"); + for (size_t i = 0; i < char_codes.size(); ++i) { + uint32_t char_code = char_codes[i]; + if (char_code == static_cast<uint32_t>(-1)) + continue; + + bool is_vertical_glyph = false; + results.emplace_back(); + TextCharPos& text_char_pos = results.back(); + if (cid_font) + text_char_pos.m_bFontStyle = true; + WideString unicode = font->UnicodeFromCharCode(char_code); + text_char_pos.m_Unicode = !unicode.IsEmpty() ? unicode[0] : char_code; + text_char_pos.m_GlyphIndex = + font->GlyphFromCharCode(char_code, &is_vertical_glyph); + uint32_t glyph_id = text_char_pos.m_GlyphIndex; +#if BUILDFLAG(IS_APPLE) + text_char_pos.m_ExtGID = font->GlyphFromCharCodeExt(char_code); + glyph_id = text_char_pos.m_ExtGID != static_cast<uint32_t>(-1) + ? text_char_pos.m_ExtGID + : text_char_pos.m_GlyphIndex; +#endif + CFX_Font* current_font; + if (ShouldUseExistingFont(font, glyph_id, has_to_unicode)) { + current_font = font->GetFont(); + text_char_pos.m_FallbackFontPosition = -1; + } else { + int32_t fallback_position = font->FallbackFontFromCharcode(char_code); + current_font = font->GetFontFallback(fallback_position); + text_char_pos.m_FallbackFontPosition = fallback_position; + text_char_pos.m_GlyphIndex = + font->FallbackGlyphFromCharcode(fallback_position, char_code); +#if BUILDFLAG(IS_APPLE) + text_char_pos.m_ExtGID = text_char_pos.m_GlyphIndex; +#endif + } + + if (!font->IsEmbedded() && !font->IsCIDFont()) + text_char_pos.m_FontCharWidth = font->GetCharWidthF(char_code); + else + text_char_pos.m_FontCharWidth = 0; + + text_char_pos.m_Origin = CFX_PointF(i > 0 ? char_pos[i - 1] : 0, 0); + text_char_pos.m_bGlyphAdjust = false; + + float scaling_factor = 1.0f; + if (ApplyGlyphSpacingHeuristic(font, current_font, is_vertical_writing)) { + int pdf_glyph_width = font->GetCharWidthF(char_code); + int font_glyph_width = + current_font->GetGlyphWidth(text_char_pos.m_GlyphIndex); + if (font_glyph_width && pdf_glyph_width > font_glyph_width + 1) { + // Move the initial x position by half of the excess (transformed to + // text space coordinates). + text_char_pos.m_Origin.x += + (pdf_glyph_width - font_glyph_width) * font_size / 2000.0f; + } else if (pdf_glyph_width && font_glyph_width && + pdf_glyph_width < font_glyph_width) { + scaling_factor = static_cast<float>(pdf_glyph_width) / font_glyph_width; + text_char_pos.m_AdjustMatrix[0] = scaling_factor; + text_char_pos.m_AdjustMatrix[1] = 0.0f; + text_char_pos.m_AdjustMatrix[2] = 0.0f; + text_char_pos.m_AdjustMatrix[3] = 1.0f; + text_char_pos.m_bGlyphAdjust = true; + } + } + if (!cid_font) + continue; + + uint16_t cid = cid_font->CIDFromCharCode(char_code); + if (is_vertical_writing) { + text_char_pos.m_Origin = CFX_PointF(0, text_char_pos.m_Origin.x); + + CFX_Point16 vertical_origin = cid_font->GetVertOrigin(cid); + text_char_pos.m_Origin.x -= font_size * vertical_origin.x / 1000; + text_char_pos.m_Origin.y -= font_size * vertical_origin.y / 1000; + } + + const uint8_t* cid_transform = cid_font->GetCIDTransform(cid); + if (cid_transform && !is_vertical_glyph) { + text_char_pos.m_AdjustMatrix[0] = + cid_font->CIDTransformToFloat(cid_transform[0]) * scaling_factor; + text_char_pos.m_AdjustMatrix[1] = + cid_font->CIDTransformToFloat(cid_transform[1]) * scaling_factor; + text_char_pos.m_AdjustMatrix[2] = + cid_font->CIDTransformToFloat(cid_transform[2]); + text_char_pos.m_AdjustMatrix[3] = + cid_font->CIDTransformToFloat(cid_transform[3]); + text_char_pos.m_Origin.x += + cid_font->CIDTransformToFloat(cid_transform[4]) * font_size; + text_char_pos.m_Origin.y += + cid_font->CIDTransformToFloat(cid_transform[5]) * font_size; + text_char_pos.m_bGlyphAdjust = true; + } + } + + return results; +}
diff --git a/core/fpdfapi/render/charposlist.h b/core/fpdfapi/render/charposlist.h new file mode 100644 index 0000000..af0ea6d --- /dev/null +++ b/core/fpdfapi/render/charposlist.h
@@ -0,0 +1,24 @@ +// Copyright 2016 The PDFium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com + +#ifndef CORE_FPDFAPI_RENDER_CHARPOSLIST_H_ +#define CORE_FPDFAPI_RENDER_CHARPOSLIST_H_ + +#include <stdint.h> + +#include <vector> + +#include "third_party/base/span.h" + +class CPDF_Font; +class TextCharPos; + +std::vector<TextCharPos> GetCharPosList(pdfium::span<const uint32_t> char_codes, + pdfium::span<const float> char_pos, + CPDF_Font* font, + float font_size); + +#endif // CORE_FPDFAPI_RENDER_CHARPOSLIST_H_
diff --git a/core/fpdfapi/render/cpdf_charposlist.cpp b/core/fpdfapi/render/cpdf_charposlist.cpp deleted file mode 100644 index b8d0cf2..0000000 --- a/core/fpdfapi/render/cpdf_charposlist.cpp +++ /dev/null
@@ -1,140 +0,0 @@ -// Copyright 2016 PDFium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com - -#include "core/fpdfapi/render/cpdf_charposlist.h" - -#include "build/build_config.h" -#include "core/fpdfapi/font/cpdf_cidfont.h" -#include "core/fpdfapi/font/cpdf_font.h" -#include "core/fxge/cfx_substfont.h" -#include "core/fxge/text_char_pos.h" - -CPDF_CharPosList::CPDF_CharPosList(const std::vector<uint32_t>& charCodes, - const std::vector<float>& charPos, - CPDF_Font* pFont, - float font_size) { - m_CharPos.reserve(charCodes.size()); - CPDF_CIDFont* pCIDFont = pFont->AsCIDFont(); - bool bVertWriting = pCIDFont && pCIDFont->IsVertWriting(); - bool bToUnicode = !!pFont->GetFontDict()->GetStreamFor("ToUnicode"); - for (size_t i = 0; i < charCodes.size(); ++i) { - uint32_t CharCode = charCodes[i]; - if (CharCode == static_cast<uint32_t>(-1)) - continue; - - bool bVert = false; - m_CharPos.emplace_back(); - TextCharPos& charpos = m_CharPos.back(); - if (pCIDFont) - charpos.m_bFontStyle = true; - WideString unicode = pFont->UnicodeFromCharCode(CharCode); - charpos.m_Unicode = !unicode.IsEmpty() ? unicode[0] : CharCode; - charpos.m_GlyphIndex = pFont->GlyphFromCharCode(CharCode, &bVert); - uint32_t GlyphID = charpos.m_GlyphIndex; -#if defined(OS_MACOSX) - charpos.m_ExtGID = pFont->GlyphFromCharCodeExt(CharCode); - GlyphID = charpos.m_ExtGID != static_cast<uint32_t>(-1) - ? charpos.m_ExtGID - : charpos.m_GlyphIndex; -#endif - bool bIsInvalidGlyph = GlyphID == static_cast<uint32_t>(-1); - bool bIsTrueTypeZeroGlyph = GlyphID == 0 && pFont->IsTrueTypeFont(); - bool bUseFallbackFont = false; - if (bIsInvalidGlyph || bIsTrueTypeZeroGlyph) { - charpos.m_FallbackFontPosition = - pFont->FallbackFontFromCharcode(CharCode); - charpos.m_GlyphIndex = pFont->FallbackGlyphFromCharcode( - charpos.m_FallbackFontPosition, CharCode); - if (bIsTrueTypeZeroGlyph && - charpos.m_GlyphIndex == static_cast<uint32_t>(-1)) { - // For a TrueType font character, when finding the glyph from the - // fallback font fails, switch back to using the original font. - - // When keyword "ToUnicode" exists in the PDF file, it indicates - // a "ToUnicode" mapping file is used to convert from CIDs (which - // begins at decimal 0) to Unicode code. (See ToUnicode Mapping File - // Tutorial - Adobe - // https://www.adobe.com/content/dam/acom/en/devnet/acrobat/pdfs/5411.ToUnicode.pdf - // and - // https://www.freetype.org/freetype2/docs/tutorial/step1.html#section-6) - if (bToUnicode) - charpos.m_GlyphIndex = 0; - } else { - bUseFallbackFont = true; - } - } - CFX_Font* pCurrentFont; - if (bUseFallbackFont) { - pCurrentFont = pFont->GetFontFallback(charpos.m_FallbackFontPosition); -#if defined(OS_MACOSX) - charpos.m_ExtGID = charpos.m_GlyphIndex; -#endif - } else { - pCurrentFont = pFont->GetFont(); - charpos.m_FallbackFontPosition = -1; - } - - if (!pFont->IsEmbedded() && !pFont->IsCIDFont()) - charpos.m_FontCharWidth = pFont->GetCharWidthF(CharCode); - else - charpos.m_FontCharWidth = 0; - - charpos.m_Origin = CFX_PointF(i > 0 ? charPos[i - 1] : 0, 0); - charpos.m_bGlyphAdjust = false; - - float scalingFactor = 1.0f; - if (!pFont->IsEmbedded() && pFont->HasFontWidths() && !bVertWriting && - !pCurrentFont->GetSubstFont()->m_bFlagMM) { - uint32_t pdfGlyphWidth = pFont->GetCharWidthF(CharCode); - uint32_t ftGlyphWidth = - pCurrentFont ? pCurrentFont->GetGlyphWidth(charpos.m_GlyphIndex) : 0; - if (ftGlyphWidth && pdfGlyphWidth > ftGlyphWidth + 1) { - // Move the initial x position by half of the excess (transformed to - // text space coordinates). - charpos.m_Origin.x += - (pdfGlyphWidth - ftGlyphWidth) * font_size / 2000.0f; - } else if (pdfGlyphWidth && ftGlyphWidth && - pdfGlyphWidth < ftGlyphWidth) { - scalingFactor = static_cast<float>(pdfGlyphWidth) / ftGlyphWidth; - charpos.m_AdjustMatrix[0] = scalingFactor; - charpos.m_AdjustMatrix[1] = 0.0f; - charpos.m_AdjustMatrix[2] = 0.0f; - charpos.m_AdjustMatrix[3] = 1.0f; - charpos.m_bGlyphAdjust = true; - } - } - if (!pCIDFont) - continue; - - uint16_t CID = pCIDFont->CIDFromCharCode(CharCode); - if (bVertWriting) { - charpos.m_Origin = CFX_PointF(0, charpos.m_Origin.x); - - short vx; - short vy; - pCIDFont->GetVertOrigin(CID, vx, vy); - charpos.m_Origin.x -= font_size * vx / 1000; - charpos.m_Origin.y -= font_size * vy / 1000; - } - - const uint8_t* pTransform = pCIDFont->GetCIDTransform(CID); - if (pTransform && !bVert) { - charpos.m_AdjustMatrix[0] = - pCIDFont->CIDTransformToFloat(pTransform[0]) * scalingFactor; - charpos.m_AdjustMatrix[1] = - pCIDFont->CIDTransformToFloat(pTransform[1]) * scalingFactor; - charpos.m_AdjustMatrix[2] = pCIDFont->CIDTransformToFloat(pTransform[2]); - charpos.m_AdjustMatrix[3] = pCIDFont->CIDTransformToFloat(pTransform[3]); - charpos.m_Origin.x += - pCIDFont->CIDTransformToFloat(pTransform[4]) * font_size; - charpos.m_Origin.y += - pCIDFont->CIDTransformToFloat(pTransform[5]) * font_size; - charpos.m_bGlyphAdjust = true; - } - } -} - -CPDF_CharPosList::~CPDF_CharPosList() = default;
diff --git a/core/fpdfapi/render/cpdf_charposlist.h b/core/fpdfapi/render/cpdf_charposlist.h deleted file mode 100644 index b06fcfc..0000000 --- a/core/fpdfapi/render/cpdf_charposlist.h +++ /dev/null
@@ -1,31 +0,0 @@ -// Copyright 2016 PDFium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com - -#ifndef CORE_FPDFAPI_RENDER_CPDF_CHARPOSLIST_H_ -#define CORE_FPDFAPI_RENDER_CPDF_CHARPOSLIST_H_ - -#include <vector> - -#include "core/fxcrt/fx_system.h" - -class CPDF_Font; -class TextCharPos; - -class CPDF_CharPosList { - public: - CPDF_CharPosList(const std::vector<uint32_t>& charCodes, - const std::vector<float>& charPos, - CPDF_Font* pFont, - float font_size); - ~CPDF_CharPosList(); - - const std::vector<TextCharPos>& Get() const { return m_CharPos; } - - private: - std::vector<TextCharPos> m_CharPos; -}; - -#endif // CORE_FPDFAPI_RENDER_CPDF_CHARPOSLIST_H_
diff --git a/core/fpdfapi/render/cpdf_devicebuffer.cpp b/core/fpdfapi/render/cpdf_devicebuffer.cpp index 3426f01..b7722f1 100644 --- a/core/fpdfapi/render/cpdf_devicebuffer.cpp +++ b/core/fpdfapi/render/cpdf_devicebuffer.cpp
@@ -1,4 +1,4 @@ -// Copyright 2016 PDFium Authors. All rights reserved. +// Copyright 2016 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -8,16 +8,17 @@ #include "build/build_config.h" #include "core/fpdfapi/page/cpdf_pageobject.h" +#include "core/fpdfapi/parser/cpdf_dictionary.h" #include "core/fpdfapi/render/cpdf_rendercontext.h" #include "core/fpdfapi/render/cpdf_renderoptions.h" #include "core/fxge/cfx_defaultrenderdevice.h" #include "core/fxge/cfx_renderdevice.h" #include "core/fxge/dib/cfx_dibitmap.h" -#include "core/fxge/fx_dib.h" +#include "core/fxge/dib/fx_dib.h" namespace { -#if defined(OS_MACOSX) +#if BUILDFLAG(IS_APPLE) constexpr bool kScaleDeviceBuffer = false; #else constexpr bool kScaleDeviceBuffer = true; @@ -67,7 +68,7 @@ FX_RECT bitmap_rect = m_Matrix.TransformRect(CFX_FloatRect(m_Rect)).GetOuterRect(); return m_pBitmap->Create(bitmap_rect.Width(), bitmap_rect.Height(), - FXDIB_Argb); + FXDIB_Format::kArgb); } void CPDF_DeviceBuffer::OutputToDevice() { @@ -83,7 +84,7 @@ auto pBuffer = pdfium::MakeRetain<CFX_DIBitmap>(); m_pDevice->CreateCompatibleBitmap(pBuffer, m_pBitmap->GetWidth(), m_pBitmap->GetHeight()); - m_pContext->GetBackground(pBuffer, m_pObject.Get(), nullptr, m_Matrix); + m_pContext->GetBackground(pBuffer, m_pObject, nullptr, m_Matrix); pBuffer->CompositeBitmap(0, 0, pBuffer->GetWidth(), pBuffer->GetHeight(), m_pBitmap, 0, 0, BlendMode::kNormal, nullptr, false); m_pDevice->StretchDIBits(pBuffer, m_Rect.left, m_Rect.top, m_Rect.Width(),
diff --git a/core/fpdfapi/render/cpdf_devicebuffer.h b/core/fpdfapi/render/cpdf_devicebuffer.h index 1f16dbe..1084465 100644 --- a/core/fpdfapi/render/cpdf_devicebuffer.h +++ b/core/fpdfapi/render/cpdf_devicebuffer.h
@@ -1,4 +1,4 @@ -// Copyright 2016 PDFium Authors. All rights reserved. +// Copyright 2016 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file.
diff --git a/core/fpdfapi/render/cpdf_docrenderdata.cpp b/core/fpdfapi/render/cpdf_docrenderdata.cpp index ba702b7..e63d54d 100644 --- a/core/fpdfapi/render/cpdf_docrenderdata.cpp +++ b/core/fpdfapi/render/cpdf_docrenderdata.cpp
@@ -1,4 +1,4 @@ -// Copyright 2016 PDFium Authors. All rights reserved. +// Copyright 2016 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -6,10 +6,12 @@ #include "core/fpdfapi/render/cpdf_docrenderdata.h" +#include <stdint.h> + +#include <algorithm> #include <array> #include <memory> #include <utility> -#include <vector> #include "core/fpdfapi/font/cpdf_type3font.h" #include "core/fpdfapi/page/cpdf_dib.h" @@ -18,6 +20,11 @@ #include "core/fpdfapi/parser/cpdf_array.h" #include "core/fpdfapi/parser/cpdf_document.h" #include "core/fpdfapi/render/cpdf_type3cache.h" +#include "core/fxcrt/fixed_uninit_data_vector.h" + +#if BUILDFLAG(IS_WIN) +#include "core/fxge/win32/cfx_psfonttracker.h" +#endif namespace { @@ -47,7 +54,7 @@ } RetainPtr<CPDF_TransferFunc> CPDF_DocRenderData::GetTransferFunc( - const CPDF_Object* pObj) { + RetainPtr<const CPDF_Object> pObj) { if (!pObj) return nullptr; @@ -60,8 +67,16 @@ return pFunc; } +#if BUILDFLAG(IS_WIN) +CFX_PSFontTracker* CPDF_DocRenderData::GetPSFontTracker() { + if (!m_PSFontTracker) + m_PSFontTracker = std::make_unique<CFX_PSFontTracker>(); + return m_PSFontTracker.get(); +} +#endif + RetainPtr<CPDF_TransferFunc> CPDF_DocRenderData::CreateTransferFunc( - const CPDF_Object* pObj) const { + RetainPtr<const CPDF_Object> pObj) const { std::unique_ptr<CPDF_Function> pFuncs[3]; const CPDF_Array* pArray = pObj->AsArray(); if (pArray) { @@ -79,42 +94,48 @@ return nullptr; } - int noutput; float output[kMaxOutputs]; - memset(output, 0, sizeof(output)); + std::fill(std::begin(output), std::end(output), 0.0f); bool bIdentity = true; - std::vector<uint8_t> samples_r(CPDF_TransferFunc::kChannelSampleSize); - std::vector<uint8_t> samples_g(CPDF_TransferFunc::kChannelSampleSize); - std::vector<uint8_t> samples_b(CPDF_TransferFunc::kChannelSampleSize); - std::array<pdfium::span<uint8_t>, 3> samples = {samples_r, samples_g, - samples_b}; - for (size_t v = 0; v < CPDF_TransferFunc::kChannelSampleSize; ++v) { - float input = static_cast<float>(v) / 255.0f; - if (pArray) { + FixedUninitDataVector<uint8_t> samples_r( + CPDF_TransferFunc::kChannelSampleSize); + FixedUninitDataVector<uint8_t> samples_g( + CPDF_TransferFunc::kChannelSampleSize); + FixedUninitDataVector<uint8_t> samples_b( + CPDF_TransferFunc::kChannelSampleSize); + std::array<pdfium::span<uint8_t>, 3> samples = {samples_r.writable_span(), + samples_g.writable_span(), + samples_b.writable_span()}; + if (pArray) { + for (size_t v = 0; v < CPDF_TransferFunc::kChannelSampleSize; ++v) { + float input = static_cast<float>(v) / 255.0f; for (int i = 0; i < 3; ++i) { if (pFuncs[i]->CountOutputs() > kMaxOutputs) { samples[i][v] = v; continue; } - pFuncs[i]->Call(&input, 1, output, &noutput); + pFuncs[i]->Call(pdfium::make_span(&input, 1), output); size_t o = FXSYS_roundf(output[0] * 255); if (o != v) bIdentity = false; samples[i][v] = o; } - continue; } - if (pFuncs[0]->CountOutputs() <= kMaxOutputs) - pFuncs[0]->Call(&input, 1, output, &noutput); - size_t o = FXSYS_roundf(output[0] * 255); - if (o != v) - bIdentity = false; - for (auto& channel : samples) - channel[v] = o; + } else { + for (size_t v = 0; v < CPDF_TransferFunc::kChannelSampleSize; ++v) { + float input = static_cast<float>(v) / 255.0f; + if (pFuncs[0]->CountOutputs() <= kMaxOutputs) + pFuncs[0]->Call(pdfium::make_span(&input, 1), output); + size_t o = FXSYS_roundf(output[0] * 255); + if (o != v) + bIdentity = false; + for (auto& channel : samples) + channel[v] = o; + } } - return pdfium::MakeRetain<CPDF_TransferFunc>( - GetDocument(), bIdentity, std::move(samples_r), std::move(samples_g), - std::move(samples_b)); + return pdfium::MakeRetain<CPDF_TransferFunc>(bIdentity, std::move(samples_r), + std::move(samples_g), + std::move(samples_b)); }
diff --git a/core/fpdfapi/render/cpdf_docrenderdata.h b/core/fpdfapi/render/cpdf_docrenderdata.h index 32b90a3..1208931 100644 --- a/core/fpdfapi/render/cpdf_docrenderdata.h +++ b/core/fpdfapi/render/cpdf_docrenderdata.h
@@ -1,4 +1,4 @@ -// Copyright 2016 PDFium Authors. All rights reserved. +// Copyright 2016 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -7,18 +7,28 @@ #ifndef CORE_FPDFAPI_RENDER_CPDF_DOCRENDERDATA_H_ #define CORE_FPDFAPI_RENDER_CPDF_DOCRENDERDATA_H_ +#include <functional> #include <map> +#include "build/build_config.h" #include "core/fpdfapi/parser/cpdf_document.h" #include "core/fxcrt/observed_ptr.h" #include "core/fxcrt/retain_ptr.h" +#if BUILDFLAG(IS_WIN) +#include <memory> +#endif + class CPDF_Font; class CPDF_Object; class CPDF_TransferFunc; class CPDF_Type3Cache; class CPDF_Type3Font; +#if BUILDFLAG(IS_WIN) +class CFX_PSFontTracker; +#endif + class CPDF_DocRenderData : public CPDF_Document::RenderDataIface { public: static CPDF_DocRenderData* FromDocument(const CPDF_Document* pDoc); @@ -30,17 +40,29 @@ CPDF_DocRenderData& operator=(const CPDF_DocRenderData&) = delete; RetainPtr<CPDF_Type3Cache> GetCachedType3(CPDF_Type3Font* pFont); - RetainPtr<CPDF_TransferFunc> GetTransferFunc(const CPDF_Object* pObj); + RetainPtr<CPDF_TransferFunc> GetTransferFunc( + RetainPtr<const CPDF_Object> pObj); + +#if BUILDFLAG(IS_WIN) + CFX_PSFontTracker* GetPSFontTracker(); +#endif protected: // protected for use by test subclasses. RetainPtr<CPDF_TransferFunc> CreateTransferFunc( - const CPDF_Object* pObj) const; + RetainPtr<const CPDF_Object> pObj) const; private: + // TODO(tsepez): investigate this map outliving its font keys. std::map<CPDF_Font*, ObservedPtr<CPDF_Type3Cache>> m_Type3FaceMap; - std::map<const CPDF_Object*, ObservedPtr<CPDF_TransferFunc>> + std::map<RetainPtr<const CPDF_Object>, + ObservedPtr<CPDF_TransferFunc>, + std::less<>> m_TransferFuncMap; + +#if BUILDFLAG(IS_WIN) + std::unique_ptr<CFX_PSFontTracker> m_PSFontTracker; +#endif }; #endif // CORE_FPDFAPI_RENDER_CPDF_DOCRENDERDATA_H_
diff --git a/core/fpdfapi/render/cpdf_docrenderdata_unittest.cpp b/core/fpdfapi/render/cpdf_docrenderdata_unittest.cpp index 2fb25b6..df7bb1c 100644 --- a/core/fpdfapi/render/cpdf_docrenderdata_unittest.cpp +++ b/core/fpdfapi/render/cpdf_docrenderdata_unittest.cpp
@@ -1,9 +1,10 @@ -// Copyright 2018 PDFium Authors. All rights reserved. +// Copyright 2018 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "core/fpdfapi/render/cpdf_docrenderdata.h" +#include <iterator> #include <memory> #include <utility> @@ -12,9 +13,8 @@ #include "core/fpdfapi/parser/cpdf_dictionary.h" #include "core/fpdfapi/parser/cpdf_number.h" #include "core/fpdfapi/parser/cpdf_stream.h" -#include "core/fxcrt/fx_memory_wrappers.h" +#include "core/fxcrt/data_vector.h" #include "testing/gtest/include/gtest/gtest.h" -#include "third_party/base/ptr_util.h" namespace { @@ -73,26 +73,23 @@ RetainPtr<CPDF_Stream> CreateType0FunctionStream() { auto func_dict = pdfium::MakeRetain<CPDF_Dictionary>(); func_dict->SetNewFor<CPDF_Number>("FunctionType", 0); - - CPDF_Array* domain_array = func_dict->SetNewFor<CPDF_Array>("Domain"); - domain_array->AddNew<CPDF_Number>(0); - domain_array->AddNew<CPDF_Number>(1); - - CPDF_Array* range_array = func_dict->SetNewFor<CPDF_Array>("Range"); - range_array->AddNew<CPDF_Number>(0); - range_array->AddNew<CPDF_Number>(0.5f); - - CPDF_Array* size_array = func_dict->SetNewFor<CPDF_Array>("Size"); - size_array->AddNew<CPDF_Number>(4); - func_dict->SetNewFor<CPDF_Number>("BitsPerSample", 8); - static const char content[] = "1234"; - size_t len = FX_ArraySize(content); - std::unique_ptr<uint8_t, FxFreeDeleter> buf(FX_Alloc(uint8_t, len)); - memcpy(buf.get(), content, len); - return pdfium::MakeRetain<CPDF_Stream>(std::move(buf), len, - std::move(func_dict)); + auto domain_array = func_dict->SetNewFor<CPDF_Array>("Domain"); + domain_array->AppendNew<CPDF_Number>(0); + domain_array->AppendNew<CPDF_Number>(1); + + auto range_array = func_dict->SetNewFor<CPDF_Array>("Range"); + range_array->AppendNew<CPDF_Number>(0); + range_array->AppendNew<CPDF_Number>(0.5f); + + auto size_array = func_dict->SetNewFor<CPDF_Array>("Size"); + size_array->AppendNew<CPDF_Number>(4); + + static constexpr uint8_t kContents[] = "1234"; + return pdfium::MakeRetain<CPDF_Stream>( + DataVector<uint8_t>(std::begin(kContents), std::end(kContents)), + std::move(func_dict)); } RetainPtr<CPDF_Dictionary> CreateType2FunctionDict() { @@ -100,19 +97,19 @@ func_dict->SetNewFor<CPDF_Number>("FunctionType", 2); func_dict->SetNewFor<CPDF_Number>("N", 1); - CPDF_Array* domain_array = func_dict->SetNewFor<CPDF_Array>("Domain"); - domain_array->AddNew<CPDF_Number>(0); - domain_array->AddNew<CPDF_Number>(1); + auto domain_array = func_dict->SetNewFor<CPDF_Array>("Domain"); + domain_array->AppendNew<CPDF_Number>(0); + domain_array->AppendNew<CPDF_Number>(1); - CPDF_Array* c0_array = func_dict->SetNewFor<CPDF_Array>("C0"); - c0_array->AddNew<CPDF_Number>(0.1f); - c0_array->AddNew<CPDF_Number>(0.2f); - c0_array->AddNew<CPDF_Number>(0.8f); + auto c0_array = func_dict->SetNewFor<CPDF_Array>("C0"); + c0_array->AppendNew<CPDF_Number>(0.1f); + c0_array->AppendNew<CPDF_Number>(0.2f); + c0_array->AppendNew<CPDF_Number>(0.8f); - CPDF_Array* c1_array = func_dict->SetNewFor<CPDF_Array>("C1"); - c1_array->AddNew<CPDF_Number>(0.05f); - c1_array->AddNew<CPDF_Number>(0.01f); - c1_array->AddNew<CPDF_Number>(0.4f); + auto c1_array = func_dict->SetNewFor<CPDF_Array>("C1"); + c1_array->AppendNew<CPDF_Number>(0.05f); + c1_array->AppendNew<CPDF_Number>(0.01f); + c1_array->AppendNew<CPDF_Number>(0.4f); return func_dict; } @@ -121,49 +118,45 @@ auto func_dict = pdfium::MakeRetain<CPDF_Dictionary>(); func_dict->SetNewFor<CPDF_Number>("FunctionType", 4); - CPDF_Array* domain_array = func_dict->SetNewFor<CPDF_Array>("Domain"); - domain_array->AddNew<CPDF_Number>(0); - domain_array->AddNew<CPDF_Number>(1); + auto domain_array = func_dict->SetNewFor<CPDF_Array>("Domain"); + domain_array->AppendNew<CPDF_Number>(0); + domain_array->AppendNew<CPDF_Number>(1); - CPDF_Array* range_array = func_dict->SetNewFor<CPDF_Array>("Range"); - range_array->AddNew<CPDF_Number>(-1); - range_array->AddNew<CPDF_Number>(1); + auto range_array = func_dict->SetNewFor<CPDF_Array>("Range"); + range_array->AppendNew<CPDF_Number>(-1); + range_array->AppendNew<CPDF_Number>(1); - static const char content[] = "{ 360 mul sin 2 div }"; - size_t len = FX_ArraySize(content); - std::unique_ptr<uint8_t, FxFreeDeleter> buf(FX_Alloc(uint8_t, len)); - memcpy(buf.get(), content, len); - return pdfium::MakeRetain<CPDF_Stream>(std::move(buf), len, - std::move(func_dict)); + static constexpr uint8_t kContents[] = "{ 360 mul sin 2 div }"; + return pdfium::MakeRetain<CPDF_Stream>( + DataVector<uint8_t>(std::begin(kContents), std::end(kContents)), + std::move(func_dict)); } RetainPtr<CPDF_Stream> CreateBadType4FunctionStream() { auto func_dict = pdfium::MakeRetain<CPDF_Dictionary>(); func_dict->SetNewFor<CPDF_Number>("FunctionType", 4); - CPDF_Array* domain_array = func_dict->SetNewFor<CPDF_Array>("Domain"); - domain_array->AddNew<CPDF_Number>(0); - domain_array->AddNew<CPDF_Number>(1); + auto domain_array = func_dict->SetNewFor<CPDF_Array>("Domain"); + domain_array->AppendNew<CPDF_Number>(0); + domain_array->AppendNew<CPDF_Number>(1); - CPDF_Array* range_array = func_dict->SetNewFor<CPDF_Array>("Range"); - range_array->AddNew<CPDF_Number>(-1); - range_array->AddNew<CPDF_Number>(1); + auto range_array = func_dict->SetNewFor<CPDF_Array>("Range"); + range_array->AppendNew<CPDF_Number>(-1); + range_array->AppendNew<CPDF_Number>(1); - static const char content[] = "garbage"; - size_t len = FX_ArraySize(content); - std::unique_ptr<uint8_t, FxFreeDeleter> buf(FX_Alloc(uint8_t, len)); - memcpy(buf.get(), content, len); - return pdfium::MakeRetain<CPDF_Stream>(std::move(buf), len, - std::move(func_dict)); + static constexpr uint8_t kContents[] = "garbage"; + return pdfium::MakeRetain<CPDF_Stream>( + DataVector<uint8_t>(std::begin(kContents), std::end(kContents)), + std::move(func_dict)); } class TestDocRenderData : public CPDF_DocRenderData { public: - TestDocRenderData() : CPDF_DocRenderData() {} + TestDocRenderData() = default; RetainPtr<CPDF_TransferFunc> CreateTransferFuncForTesting( - const CPDF_Object* pObj) const { - return CreateTransferFunc(pObj); + RetainPtr<const CPDF_Object> pObj) const { + return CreateTransferFunc(std::move(pObj)); } }; @@ -171,18 +164,18 @@ RetainPtr<CPDF_Dictionary> func_dict = CreateType2FunctionDict(); TestDocRenderData render_data; - auto func = render_data.CreateTransferFuncForTesting(func_dict.Get()); + auto func = render_data.CreateTransferFuncForTesting(func_dict); ASSERT_TRUE(func); EXPECT_FALSE(func->GetIdentity()); auto r_samples = func->GetSamplesR(); auto g_samples = func->GetSamplesG(); auto b_samples = func->GetSamplesB(); - ASSERT_EQ(FX_ArraySize(kExpectedType2FunctionSamples), r_samples.size()); - ASSERT_EQ(FX_ArraySize(kExpectedType2FunctionSamples), g_samples.size()); - ASSERT_EQ(FX_ArraySize(kExpectedType2FunctionSamples), b_samples.size()); + ASSERT_EQ(std::size(kExpectedType2FunctionSamples), r_samples.size()); + ASSERT_EQ(std::size(kExpectedType2FunctionSamples), g_samples.size()); + ASSERT_EQ(std::size(kExpectedType2FunctionSamples), b_samples.size()); - for (size_t i = 0; i < FX_ArraySize(kExpectedType2FunctionSamples); ++i) { + for (size_t i = 0; i < std::size(kExpectedType2FunctionSamples); ++i) { EXPECT_EQ(kExpectedType2FunctionSamples[i], r_samples[i]); EXPECT_EQ(kExpectedType2FunctionSamples[i], g_samples[i]); EXPECT_EQ(kExpectedType2FunctionSamples[i], b_samples[i]); @@ -202,23 +195,23 @@ TEST(CPDF_DocRenderDataTest, TransferFunctionArray) { auto func_array = pdfium::MakeRetain<CPDF_Array>(); - func_array->Add(CreateType0FunctionStream()); - func_array->Add(CreateType2FunctionDict()); - func_array->Add(CreateType4FunctionStream()); + func_array->Append(CreateType0FunctionStream()); + func_array->Append(CreateType2FunctionDict()); + func_array->Append(CreateType4FunctionStream()); TestDocRenderData render_data; - auto func = render_data.CreateTransferFuncForTesting(func_array.Get()); + auto func = render_data.CreateTransferFuncForTesting(func_array); ASSERT_TRUE(func); EXPECT_FALSE(func->GetIdentity()); auto r_samples = func->GetSamplesR(); auto g_samples = func->GetSamplesG(); auto b_samples = func->GetSamplesB(); - ASSERT_EQ(FX_ArraySize(kExpectedType0FunctionSamples), r_samples.size()); - ASSERT_EQ(FX_ArraySize(kExpectedType2FunctionSamples), g_samples.size()); - ASSERT_EQ(FX_ArraySize(kExpectedType4FunctionSamples), b_samples.size()); + ASSERT_EQ(std::size(kExpectedType0FunctionSamples), r_samples.size()); + ASSERT_EQ(std::size(kExpectedType2FunctionSamples), g_samples.size()); + ASSERT_EQ(std::size(kExpectedType4FunctionSamples), b_samples.size()); - for (size_t i = 0; i < FX_ArraySize(kExpectedType2FunctionSamples); ++i) { + for (size_t i = 0; i < std::size(kExpectedType2FunctionSamples); ++i) { EXPECT_EQ(kExpectedType0FunctionSamples[i], r_samples[i]); EXPECT_EQ(kExpectedType2FunctionSamples[i], g_samples[i]); EXPECT_EQ(kExpectedType4FunctionSamples[i], b_samples[i]); @@ -241,7 +234,7 @@ auto func_stream = CreateBadType4FunctionStream(); TestDocRenderData render_data; - auto func = render_data.CreateTransferFuncForTesting(func_stream.Get()); + auto func = render_data.CreateTransferFuncForTesting(func_stream); EXPECT_FALSE(func); } @@ -249,18 +242,18 @@ auto func_array = pdfium::MakeRetain<CPDF_Array>(); TestDocRenderData render_data; - auto func = render_data.CreateTransferFuncForTesting(func_array.Get()); + auto func = render_data.CreateTransferFuncForTesting(func_array); EXPECT_FALSE(func); } { auto func_array = pdfium::MakeRetain<CPDF_Array>(); - func_array->Add(CreateType0FunctionStream()); - func_array->Add(CreateType2FunctionDict()); - func_array->Add(CreateBadType4FunctionStream()); + func_array->Append(CreateType0FunctionStream()); + func_array->Append(CreateType2FunctionDict()); + func_array->Append(CreateBadType4FunctionStream()); TestDocRenderData render_data; - auto func = render_data.CreateTransferFuncForTesting(func_array.Get()); + auto func = render_data.CreateTransferFuncForTesting(func_array); EXPECT_FALSE(func); } }
diff --git a/core/fpdfapi/render/cpdf_imagecacheentry.cpp b/core/fpdfapi/render/cpdf_imagecacheentry.cpp deleted file mode 100644 index 3805b2d..0000000 --- a/core/fpdfapi/render/cpdf_imagecacheentry.cpp +++ /dev/null
@@ -1,124 +0,0 @@ -// Copyright 2016 PDFium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com - -#include "core/fpdfapi/render/cpdf_imagecacheentry.h" - -#include <memory> -#include <utility> - -#include "core/fpdfapi/page/cpdf_dib.h" -#include "core/fpdfapi/page/cpdf_image.h" -#include "core/fpdfapi/page/cpdf_page.h" -#include "core/fpdfapi/parser/cpdf_dictionary.h" -#include "core/fpdfapi/parser/cpdf_document.h" -#include "core/fpdfapi/parser/cpdf_stream.h" -#include "core/fpdfapi/render/cpdf_pagerendercache.h" -#include "core/fpdfapi/render/cpdf_rendercontext.h" -#include "core/fpdfapi/render/cpdf_renderstatus.h" -#include "core/fxge/dib/cfx_dibitmap.h" - -namespace { - -uint32_t GetEstimatedImageSize(const RetainPtr<CFX_DIBBase>& pDIB) { - if (!pDIB || !pDIB->GetBuffer()) - return 0; - - int height = pDIB->GetHeight(); - ASSERT(pdfium::base::IsValueInRangeForNumericType<uint32_t>(height)); - return static_cast<uint32_t>(height) * pDIB->GetPitch() + - pDIB->GetPaletteSize() * 4; -} - -} // namespace - -CPDF_ImageCacheEntry::CPDF_ImageCacheEntry(CPDF_Document* pDoc, - const RetainPtr<CPDF_Image>& pImage) - : m_pDocument(pDoc), m_pImage(pImage) {} - -CPDF_ImageCacheEntry::~CPDF_ImageCacheEntry() = default; - -void CPDF_ImageCacheEntry::Reset() { - m_pCachedBitmap.Reset(); - CalcSize(); -} - -RetainPtr<CFX_DIBBase> CPDF_ImageCacheEntry::DetachBitmap() { - return std::move(m_pCurBitmap); -} - -RetainPtr<CFX_DIBBase> CPDF_ImageCacheEntry::DetachMask() { - return std::move(m_pCurMask); -} - -CPDF_DIB::LoadState CPDF_ImageCacheEntry::StartGetCachedBitmap( - const CPDF_Dictionary* pFormResources, - CPDF_Dictionary* pPageResources, - bool bStdCS, - uint32_t GroupFamily, - bool bLoadMask, - CPDF_RenderStatus* pRenderStatus) { - ASSERT(pRenderStatus); - - if (m_pCachedBitmap) { - m_pCurBitmap = m_pCachedBitmap; - m_pCurMask = m_pCachedMask; - return CPDF_DIB::LoadState::kSuccess; - } - - m_pCurBitmap = pdfium::MakeRetain<CPDF_DIB>(); - CPDF_DIB::LoadState ret = m_pCurBitmap.As<CPDF_DIB>()->StartLoadDIBBase( - m_pDocument.Get(), m_pImage->GetStream(), true, pFormResources, - pPageResources, bStdCS, GroupFamily, bLoadMask); - if (ret == CPDF_DIB::LoadState::kContinue) - return CPDF_DIB::LoadState::kContinue; - - if (ret == CPDF_DIB::LoadState::kSuccess) - ContinueGetCachedBitmap(pRenderStatus); - else - m_pCurBitmap.Reset(); - return CPDF_DIB::LoadState::kFail; -} - -bool CPDF_ImageCacheEntry::Continue(PauseIndicatorIface* pPause, - CPDF_RenderStatus* pRenderStatus) { - CPDF_DIB::LoadState ret = - m_pCurBitmap.As<CPDF_DIB>()->ContinueLoadDIBBase(pPause); - if (ret == CPDF_DIB::LoadState::kContinue) - return true; - - if (ret == CPDF_DIB::LoadState::kSuccess) - ContinueGetCachedBitmap(pRenderStatus); - else - m_pCurBitmap.Reset(); - return false; -} - -void CPDF_ImageCacheEntry::ContinueGetCachedBitmap( - CPDF_RenderStatus* pRenderStatus) { - m_MatteColor = m_pCurBitmap.As<CPDF_DIB>()->GetMatteColor(); - m_pCurMask = m_pCurBitmap.As<CPDF_DIB>()->DetachMask(); - CPDF_RenderContext* pContext = pRenderStatus->GetContext(); - CPDF_PageRenderCache* pPageRenderCache = pContext->GetPageCache(); - m_dwTimeCount = pPageRenderCache->GetTimeCount(); - if (m_pCurBitmap->GetPitch() * m_pCurBitmap->GetHeight() < kHugeImageSize) { - m_pCachedBitmap = m_pCurBitmap->Clone(nullptr); - m_pCurBitmap.Reset(); - } else { - m_pCachedBitmap = m_pCurBitmap; - } - if (m_pCurMask) { - m_pCachedMask = m_pCurMask->Clone(nullptr); - m_pCurMask.Reset(); - } - m_pCurBitmap = m_pCachedBitmap; - m_pCurMask = m_pCachedMask; - CalcSize(); -} - -void CPDF_ImageCacheEntry::CalcSize() { - m_dwCacheSize = GetEstimatedImageSize(m_pCachedBitmap) + - GetEstimatedImageSize(m_pCachedMask); -}
diff --git a/core/fpdfapi/render/cpdf_imagecacheentry.h b/core/fpdfapi/render/cpdf_imagecacheentry.h deleted file mode 100644 index c3f373e..0000000 --- a/core/fpdfapi/render/cpdf_imagecacheentry.h +++ /dev/null
@@ -1,62 +0,0 @@ -// Copyright 2016 PDFium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com - -#ifndef CORE_FPDFAPI_RENDER_CPDF_IMAGECACHEENTRY_H_ -#define CORE_FPDFAPI_RENDER_CPDF_IMAGECACHEENTRY_H_ - -#include "core/fpdfapi/page/cpdf_dib.h" -#include "core/fxcrt/fx_system.h" -#include "core/fxcrt/retain_ptr.h" -#include "core/fxcrt/unowned_ptr.h" - -class CPDF_Dictionary; -class CPDF_Document; -class CPDF_Image; -class CPDF_RenderStatus; -class PauseIndicatorIface; - -class CPDF_ImageCacheEntry { - public: - CPDF_ImageCacheEntry(CPDF_Document* pDoc, - const RetainPtr<CPDF_Image>& pImage); - ~CPDF_ImageCacheEntry(); - - void Reset(); - uint32_t EstimateSize() const { return m_dwCacheSize; } - uint32_t GetTimeCount() const { return m_dwTimeCount; } - CPDF_Image* GetImage() const { return m_pImage.Get(); } - - CPDF_DIB::LoadState StartGetCachedBitmap( - const CPDF_Dictionary* pFormResources, - CPDF_Dictionary* pPageResources, - bool bStdCS, - uint32_t GroupFamily, - bool bLoadMask, - CPDF_RenderStatus* pRenderStatus); - - // Returns whether to Continue() or not. - bool Continue(PauseIndicatorIface* pPause, CPDF_RenderStatus* pRenderStatus); - - RetainPtr<CFX_DIBBase> DetachBitmap(); - RetainPtr<CFX_DIBBase> DetachMask(); - - int m_dwTimeCount = 0; - uint32_t m_MatteColor = 0; - - private: - void ContinueGetCachedBitmap(CPDF_RenderStatus* pRenderStatus); - void CalcSize(); - - UnownedPtr<CPDF_Document> const m_pDocument; - RetainPtr<CPDF_Image> const m_pImage; - RetainPtr<CFX_DIBBase> m_pCurBitmap; - RetainPtr<CFX_DIBBase> m_pCurMask; - RetainPtr<CFX_DIBBase> m_pCachedBitmap; - RetainPtr<CFX_DIBBase> m_pCachedMask; - uint32_t m_dwCacheSize = 0; -}; - -#endif // CORE_FPDFAPI_RENDER_CPDF_IMAGECACHEENTRY_H_
diff --git a/core/fpdfapi/render/cpdf_imageloader.cpp b/core/fpdfapi/render/cpdf_imageloader.cpp deleted file mode 100644 index fac4799..0000000 --- a/core/fpdfapi/render/cpdf_imageloader.cpp +++ /dev/null
@@ -1,79 +0,0 @@ -// Copyright 2016 PDFium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com - -#include "core/fpdfapi/render/cpdf_imageloader.h" - -#include "core/fpdfapi/page/cpdf_dib.h" -#include "core/fpdfapi/page/cpdf_image.h" -#include "core/fpdfapi/page/cpdf_imageobject.h" -#include "core/fpdfapi/page/cpdf_transferfunc.h" -#include "core/fpdfapi/render/cpdf_imagecacheentry.h" -#include "core/fpdfapi/render/cpdf_pagerendercache.h" -#include "core/fpdfapi/render/cpdf_renderstatus.h" -#include "core/fxge/dib/cfx_dibitmap.h" - -CPDF_ImageLoader::CPDF_ImageLoader() = default; - -CPDF_ImageLoader::~CPDF_ImageLoader() = default; - -bool CPDF_ImageLoader::Start(CPDF_ImageObject* pImage, - CPDF_PageRenderCache* pCache, - bool bStdCS, - uint32_t GroupFamily, - bool bLoadMask, - CPDF_RenderStatus* pRenderStatus) { - m_pCache = pCache; - m_pImageObject = pImage; - bool ret; - if (pCache) { - ret = pCache->StartGetCachedBitmap(m_pImageObject->GetImage(), bStdCS, - GroupFamily, bLoadMask, pRenderStatus); - } else { - ret = m_pImageObject->GetImage()->StartLoadDIBBase( - pRenderStatus->GetFormResource(), pRenderStatus->GetPageResource(), - bStdCS, GroupFamily, bLoadMask); - } - if (!ret) - HandleFailure(); - return ret; -} - -bool CPDF_ImageLoader::Continue(PauseIndicatorIface* pPause, - CPDF_RenderStatus* pRenderStatus) { - bool ret = m_pCache ? m_pCache->Continue(pPause, pRenderStatus) - : m_pImageObject->GetImage()->Continue(pPause); - if (!ret) - HandleFailure(); - return ret; -} - -RetainPtr<CFX_DIBBase> CPDF_ImageLoader::TranslateImage( - const RetainPtr<CPDF_TransferFunc>& pTransferFunc) { - ASSERT(pTransferFunc); - ASSERT(!pTransferFunc->GetIdentity()); - - m_pBitmap = pTransferFunc->TranslateImage(m_pBitmap); - if (m_bCached && m_pMask) - m_pMask = m_pMask->Clone(nullptr); - m_bCached = false; - return m_pBitmap; -} - -void CPDF_ImageLoader::HandleFailure() { - if (m_pCache) { - CPDF_ImageCacheEntry* entry = m_pCache->GetCurImageCacheEntry(); - m_bCached = true; - m_pBitmap = entry->DetachBitmap(); - m_pMask = entry->DetachMask(); - m_MatteColor = entry->m_MatteColor; - return; - } - RetainPtr<CPDF_Image> pImage = m_pImageObject->GetImage(); - m_bCached = false; - m_pBitmap = pImage->DetachBitmap(); - m_pMask = pImage->DetachMask(); - m_MatteColor = pImage->m_MatteColor; -}
diff --git a/core/fpdfapi/render/cpdf_imageloader.h b/core/fpdfapi/render/cpdf_imageloader.h deleted file mode 100644 index 7e12c01..0000000 --- a/core/fpdfapi/render/cpdf_imageloader.h +++ /dev/null
@@ -1,51 +0,0 @@ -// Copyright 2016 PDFium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com - -#ifndef CORE_FPDFAPI_RENDER_CPDF_IMAGELOADER_H_ -#define CORE_FPDFAPI_RENDER_CPDF_IMAGELOADER_H_ - -#include "core/fxcrt/retain_ptr.h" -#include "core/fxcrt/unowned_ptr.h" - -class CFX_DIBBase; -class CPDF_ImageObject; -class CPDF_PageRenderCache; -class CPDF_RenderStatus; -class CPDF_TransferFunc; -class PauseIndicatorIface; - -class CPDF_ImageLoader { - public: - CPDF_ImageLoader(); - ~CPDF_ImageLoader(); - - bool Start(CPDF_ImageObject* pImage, - CPDF_PageRenderCache* pCache, - bool bStdCS, - uint32_t GroupFamily, - bool bLoadMask, - CPDF_RenderStatus* pRenderStatus); - bool Continue(PauseIndicatorIface* pPause, CPDF_RenderStatus* pRenderStatus); - - RetainPtr<CFX_DIBBase> TranslateImage( - const RetainPtr<CPDF_TransferFunc>& pTransferFunc); - - const RetainPtr<CFX_DIBBase>& GetBitmap() const { return m_pBitmap; } - const RetainPtr<CFX_DIBBase>& GetMask() const { return m_pMask; } - uint32_t MatteColor() const { return m_MatteColor; } - - private: - void HandleFailure(); - - uint32_t m_MatteColor = 0; - bool m_bCached = false; - RetainPtr<CFX_DIBBase> m_pBitmap; - RetainPtr<CFX_DIBBase> m_pMask; - UnownedPtr<CPDF_PageRenderCache> m_pCache; - UnownedPtr<CPDF_ImageObject> m_pImageObject; -}; - -#endif // CORE_FPDFAPI_RENDER_CPDF_IMAGELOADER_H_
diff --git a/core/fpdfapi/render/cpdf_imagerenderer.cpp b/core/fpdfapi/render/cpdf_imagerenderer.cpp index 2d3ec4c..c5f3f1d 100644 --- a/core/fpdfapi/render/cpdf_imagerenderer.cpp +++ b/core/fpdfapi/render/cpdf_imagerenderer.cpp
@@ -1,4 +1,4 @@ -// Copyright 2016 PDFium Authors. All rights reserved. +// Copyright 2016 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -6,38 +6,43 @@ #include "core/fpdfapi/render/cpdf_imagerenderer.h" +#include <math.h> + #include <algorithm> #include <memory> +#include <utility> #include "core/fpdfapi/page/cpdf_dib.h" #include "core/fpdfapi/page/cpdf_docpagedata.h" #include "core/fpdfapi/page/cpdf_image.h" +#include "core/fpdfapi/page/cpdf_imageloader.h" #include "core/fpdfapi/page/cpdf_imageobject.h" #include "core/fpdfapi/page/cpdf_occontext.h" #include "core/fpdfapi/page/cpdf_page.h" +#include "core/fpdfapi/page/cpdf_pageimagecache.h" #include "core/fpdfapi/page/cpdf_pageobject.h" #include "core/fpdfapi/page/cpdf_shadingpattern.h" #include "core/fpdfapi/page/cpdf_tilingpattern.h" #include "core/fpdfapi/page/cpdf_transferfunc.h" -#include "core/fpdfapi/parser/cpdf_array.h" #include "core/fpdfapi/parser/cpdf_dictionary.h" #include "core/fpdfapi/parser/cpdf_document.h" #include "core/fpdfapi/parser/cpdf_stream.h" -#include "core/fpdfapi/render/cpdf_pagerendercache.h" +#include "core/fpdfapi/parser/fpdf_parser_decode.h" #include "core/fpdfapi/render/cpdf_rendercontext.h" #include "core/fpdfapi/render/cpdf_renderstatus.h" #include "core/fxcrt/fx_safe_types.h" #include "core/fxcrt/maybe_owned.h" #include "core/fxge/cfx_defaultrenderdevice.h" -#include "core/fxge/cfx_pathdata.h" +#include "core/fxge/cfx_fillrenderoptions.h" +#include "core/fxge/cfx_path.h" #include "core/fxge/dib/cfx_dibbase.h" #include "core/fxge/dib/cfx_dibitmap.h" #include "core/fxge/dib/cfx_imagestretcher.h" #include "core/fxge/dib/cfx_imagetransformer.h" -#include "third_party/base/ptr_util.h" -#include "third_party/base/stl_util.h" +#include "third_party/base/check.h" +#include "third_party/base/cxx17_backports.h" -#ifdef _SKIA_SUPPORT_ +#if defined(_SKIA_SUPPORT_) #include "core/fxge/skia/fx_skia_device.h" #endif @@ -52,9 +57,34 @@ return safe_val.ValueOrDefault(kLimit) >= kLimit; } +void ClearBitmap(CFX_DefaultRenderDevice& bitmap_device, uint32_t color) { +#if defined(_SKIA_SUPPORT_) + if (CFX_DefaultRenderDevice::SkiaIsDefaultRenderer()) { + bitmap_device.Clear(color); + return; + } +#endif + bitmap_device.GetBitmap()->Clear(color); +} + +RetainPtr<CFX_DIBBase> PreMultiplyBitmapIfAlpha( + RetainPtr<CFX_DIBBase> base_bitmap) { +#if defined(_SKIA_SUPPORT_) + if (CFX_DefaultRenderDevice::SkiaIsDefaultRenderer()) { + RetainPtr<CFX_DIBitmap> premultiplied = base_bitmap->Realize(); + if (base_bitmap->IsAlphaFormat()) + premultiplied->PreMultiply(); + return premultiplied; + } +#endif // defined(_SKIA_SUPPORT_) + return base_bitmap; +} + } // namespace -CPDF_ImageRenderer::CPDF_ImageRenderer() = default; +CPDF_ImageRenderer::CPDF_ImageRenderer(CPDF_RenderStatus* pStatus) + : m_pRenderStatus(pStatus), + m_pLoader(std::make_unique<CPDF_ImageLoader>()) {} CPDF_ImageRenderer::~CPDF_ImageRenderer() = default; @@ -62,47 +92,51 @@ if (!GetUnitRect().has_value()) return false; - if (m_Loader.Start(m_pImageObject.Get(), - m_pRenderStatus->GetContext()->GetPageCache(), m_bStdCS, - m_pRenderStatus->GetGroupFamily(), - m_pRenderStatus->GetLoadMask(), m_pRenderStatus.Get())) { - m_Mode = Mode::kDefault; - return true; + if (!m_pLoader->Start( + m_pImageObject, m_pRenderStatus->GetContext()->GetPageCache(), + m_pRenderStatus->GetFormResource(), + m_pRenderStatus->GetPageResource(), m_bStdCS, + m_pRenderStatus->GetGroupFamily(), m_pRenderStatus->GetLoadMask(), + {m_pRenderStatus->GetRenderDevice()->GetWidth(), + m_pRenderStatus->GetRenderDevice()->GetHeight()})) { + return false; } - return false; + m_Mode = Mode::kDefault; + return true; } bool CPDF_ImageRenderer::StartRenderDIBBase() { - if (!m_Loader.GetBitmap()) + if (!m_pLoader->GetBitmap()) return false; CPDF_GeneralState& state = m_pImageObject->m_GeneralState; m_BitmapAlpha = FXSYS_roundf(255 * state.GetFillAlpha()); - m_pDIBBase = m_Loader.GetBitmap(); + m_pDIBBase = m_pLoader->GetBitmap(); if (GetRenderOptions().ColorModeIs(CPDF_RenderOptions::kAlpha) && - !m_Loader.GetMask()) { + !m_pLoader->GetMask()) { return StartBitmapAlpha(); } - if (state.GetTR()) { + RetainPtr<const CPDF_Object> pTR = state.GetTR(); + if (pTR) { if (!state.GetTransferFunc()) - state.SetTransferFunc(m_pRenderStatus->GetTransferFunc(state.GetTR())); + state.SetTransferFunc(m_pRenderStatus->GetTransferFunc(std::move(pTR))); if (state.GetTransferFunc() && !state.GetTransferFunc()->GetIdentity()) - m_pDIBBase = m_Loader.TranslateImage(state.GetTransferFunc()); + m_pDIBBase = m_pLoader->TranslateImage(state.GetTransferFunc()); } m_FillArgb = 0; m_bPatternColor = false; m_pPattern = nullptr; - if (m_pDIBBase->IsAlphaMask()) { + if (m_pDIBBase->IsMaskFormat()) { const CPDF_Color* pColor = m_pImageObject->m_ColorState.GetFillColor(); if (pColor && pColor->IsPattern()) { - m_pPattern.Reset(pColor->GetPattern()); + m_pPattern = pColor->GetPattern(); if (m_pPattern) m_bPatternColor = true; } - m_FillArgb = m_pRenderStatus->GetFillArgb(m_pImageObject.Get()); + m_FillArgb = m_pRenderStatus->GetFillArgb(m_pImageObject); } else if (GetRenderOptions().ColorModeIs(CPDF_RenderOptions::kGray)) { - RetainPtr<CFX_DIBitmap> pClone = m_pDIBBase->Clone(nullptr); + RetainPtr<CFX_DIBitmap> pClone = m_pDIBBase->Realize(); if (!pClone) return false; @@ -123,7 +157,7 @@ else if (m_pImageObject->GetImage()->IsInterpol()) m_ResampleOptions.bInterpolateBilinear = true; - if (m_Loader.GetMask()) + if (m_pLoader->GetMask()) return DrawMaskedImage(); if (m_bPatternColor) @@ -142,62 +176,58 @@ } else { pDocument = m_pImageObject->GetImage()->GetDocument(); } - CPDF_Dictionary* pPageResources = - pPage ? pPage->m_pPageResources.Get() : nullptr; - CPDF_Object* pCSObj = - m_pImageObject->GetImage()->GetStream()->GetDict()->GetDirectObjectFor( - "ColorSpace"); + RetainPtr<const CPDF_Dictionary> pPageResources = + pPage ? pPage->GetPageResources() : nullptr; + RetainPtr<const CPDF_Dictionary> pStreamDict = + m_pImageObject->GetImage()->GetStream()->GetDict(); + RetainPtr<const CPDF_Object> pCSObj = + pStreamDict->GetDirectObjectFor("ColorSpace"); auto* pData = CPDF_DocPageData::FromDocument(pDocument); RetainPtr<CPDF_ColorSpace> pColorSpace = - pData->GetColorSpace(pCSObj, pPageResources); + pData->GetColorSpace(pCSObj.Get(), pPageResources); if (pColorSpace) { - int format = pColorSpace->GetFamily(); - if (format == PDFCS_DEVICECMYK || format == PDFCS_SEPARATION || - format == PDFCS_DEVICEN) { + CPDF_ColorSpace::Family format = pColorSpace->GetFamily(); + if (format == CPDF_ColorSpace::Family::kDeviceCMYK || + format == CPDF_ColorSpace::Family::kSeparation || + format == CPDF_ColorSpace::Family::kDeviceN) { m_BlendType = BlendMode::kDarken; } } return StartDIBBase(); } -bool CPDF_ImageRenderer::Start(CPDF_RenderStatus* pStatus, - CPDF_ImageObject* pImageObject, +bool CPDF_ImageRenderer::Start(CPDF_ImageObject* pImageObject, const CFX_Matrix& mtObj2Device, bool bStdCS, BlendMode blendType) { - ASSERT(pImageObject); - m_pRenderStatus = pStatus; + DCHECK(pImageObject); m_bStdCS = bStdCS; m_pImageObject = pImageObject; m_BlendType = blendType; m_mtObj2Device = mtObj2Device; - const CPDF_Dictionary* pOC = m_pImageObject->GetImage()->GetOC(); - if (pOC && GetRenderOptions().GetOCContext() && - !GetRenderOptions().GetOCContext()->CheckOCGVisible(pOC)) { + RetainPtr<const CPDF_Dictionary> pOC = m_pImageObject->GetImage()->GetOC(); + if (pOC && !GetRenderOptions().CheckOCGDictVisible(pOC)) return false; - } + m_ImageMatrix = m_pImageObject->matrix() * mtObj2Device; if (StartLoadDIBBase()) return true; + return StartRenderDIBBase(); } -bool CPDF_ImageRenderer::Start(CPDF_RenderStatus* pStatus, - const RetainPtr<CFX_DIBBase>& pDIBBase, +bool CPDF_ImageRenderer::Start(RetainPtr<CFX_DIBBase> pDIBBase, FX_ARGB bitmap_argb, - int bitmap_alpha, const CFX_Matrix& mtImage2Device, const FXDIB_ResampleOptions& options, - bool bStdCS, - BlendMode blendType) { - m_pRenderStatus = pStatus; - m_pDIBBase = pDIBBase; + bool bStdCS) { + m_pDIBBase = std::move(pDIBBase); m_FillArgb = bitmap_argb; - m_BitmapAlpha = bitmap_alpha; + m_BitmapAlpha = 255; m_ImageMatrix = mtImage2Device; m_ResampleOptions = options; m_bStdCS = bStdCS; - m_BlendType = blendType; + m_BlendType = BlendMode::kNormal; return StartDIBBase(); } @@ -222,7 +252,7 @@ void CPDF_ImageRenderer::CalculateDrawImage( CFX_DefaultRenderDevice* pBitmapDevice1, CFX_DefaultRenderDevice* pBitmapDevice2, - const RetainPtr<CFX_DIBBase>& pDIBBase, + RetainPtr<CFX_DIBBase> pDIBBase, const CFX_Matrix& mtNewMatrix, const FX_RECT& rect) const { CPDF_RenderStatus bitmap_render(m_pRenderStatus->GetContext(), @@ -231,19 +261,21 @@ bitmap_render.SetStdCS(true); bitmap_render.Initialize(nullptr, nullptr); - CPDF_ImageRenderer image_render; - if (image_render.Start(&bitmap_render, pDIBBase, 0xffffffff, 255, mtNewMatrix, - m_ResampleOptions, true, BlendMode::kNormal)) { + CPDF_ImageRenderer image_render(&bitmap_render); + if (image_render.Start(std::move(pDIBBase), 0xffffffff, mtNewMatrix, + m_ResampleOptions, true)) { image_render.Continue(nullptr); } - if (m_Loader.MatteColor() == 0xffffffff) + if (m_pLoader->MatteColor() == 0xffffffff) return; - int matte_r = FXARGB_R(m_Loader.MatteColor()); - int matte_g = FXARGB_G(m_Loader.MatteColor()); - int matte_b = FXARGB_B(m_Loader.MatteColor()); + int matte_r = FXARGB_R(m_pLoader->MatteColor()); + int matte_g = FXARGB_G(m_pLoader->MatteColor()); + int matte_b = FXARGB_B(m_pLoader->MatteColor()); for (int row = 0; row < rect.Height(); row++) { - uint8_t* dest_scan = pBitmapDevice1->GetBitmap()->GetWritableScanline(row); - const uint8_t* mask_scan = pBitmapDevice2->GetBitmap()->GetScanline(row); + uint8_t* dest_scan = + pBitmapDevice1->GetBitmap()->GetWritableScanline(row).data(); + const uint8_t* mask_scan = + pBitmapDevice2->GetBitmap()->GetScanline(row).data(); for (int col = 0; col < rect.Width(); col++) { int alpha = *mask_scan++; if (!alpha) { @@ -277,10 +309,10 @@ CFX_Matrix new_matrix = GetDrawMatrix(rect); CFX_DefaultRenderDevice bitmap_device1; - if (!bitmap_device1.Create(rect.Width(), rect.Height(), FXDIB_Rgb32, nullptr)) + if (!bitmap_device1.Create(rect.Width(), rect.Height(), FXDIB_Format::kArgb, + nullptr)) { return true; - - bitmap_device1.GetBitmap()->Clear(0xffffff); + } CPDF_RenderStatus bitmap_render(m_pRenderStatus->GetContext(), &bitmap_device1); @@ -293,23 +325,22 @@ patternDevice.Translate(static_cast<float>(-rect.left), static_cast<float>(-rect.top)); if (CPDF_TilingPattern* pTilingPattern = m_pPattern->AsTilingPattern()) { - bitmap_render.DrawTilingPattern(pTilingPattern, m_pImageObject.Get(), + bitmap_render.DrawTilingPattern(pTilingPattern, m_pImageObject, patternDevice, false); } else if (CPDF_ShadingPattern* pShadingPattern = m_pPattern->AsShadingPattern()) { - bitmap_render.DrawShadingPattern(pShadingPattern, m_pImageObject.Get(), + bitmap_render.DrawShadingPattern(pShadingPattern, m_pImageObject, patternDevice, false); } CFX_DefaultRenderDevice bitmap_device2; - if (!bitmap_device2.Create(rect.Width(), rect.Height(), FXDIB_8bppRgb, - nullptr)) { + if (!bitmap_device2.Create(rect.Width(), rect.Height(), + FXDIB_Format::k8bppRgb, nullptr)) { return true; } - bitmap_device2.GetBitmap()->Clear(0); CalculateDrawImage(&bitmap_device1, &bitmap_device2, m_pDIBBase, new_matrix, rect); - bitmap_device2.GetBitmap()->ConvertFormat(FXDIB_8bppMask); + bitmap_device2.GetBitmap()->ConvertFormat(FXDIB_Format::k8bppMask); bitmap_device1.GetBitmap()->MultiplyAlpha(bitmap_device2.GetBitmap()); bitmap_device1.GetBitmap()->MultiplyAlpha(255); m_pRenderStatus->GetRenderDevice()->SetDIBitsWithBlend( @@ -329,48 +360,41 @@ CFX_Matrix new_matrix = GetDrawMatrix(rect); CFX_DefaultRenderDevice bitmap_device1; - if (!bitmap_device1.Create(rect.Width(), rect.Height(), FXDIB_Rgb32, nullptr)) + if (!bitmap_device1.Create(rect.Width(), rect.Height(), FXDIB_Format::kRgb32, + nullptr)) { return true; - -#if defined _SKIA_SUPPORT_ - bitmap_device1.Clear(0xffffff); -#else - bitmap_device1.GetBitmap()->Clear(0xffffff); -#endif + } + ClearBitmap(bitmap_device1, 0xffffffff); CPDF_RenderStatus bitmap_render(m_pRenderStatus->GetContext(), &bitmap_device1); bitmap_render.SetDropObjects(m_pRenderStatus->GetDropObjects()); bitmap_render.SetStdCS(true); bitmap_render.Initialize(nullptr, nullptr); - CPDF_ImageRenderer image_render; - if (image_render.Start(&bitmap_render, m_pDIBBase, 0, 255, new_matrix, - m_ResampleOptions, true, BlendMode::kNormal)) { + CPDF_ImageRenderer image_render(&bitmap_render); + if (image_render.Start(m_pDIBBase, 0, new_matrix, m_ResampleOptions, true)) { image_render.Continue(nullptr); } CFX_DefaultRenderDevice bitmap_device2; - if (!bitmap_device2.Create(rect.Width(), rect.Height(), FXDIB_8bppRgb, - nullptr)) + if (!bitmap_device2.Create(rect.Width(), rect.Height(), + FXDIB_Format::k8bppRgb, nullptr)) { return true; - -#if defined _SKIA_SUPPORT_ - bitmap_device2.Clear(0); -#else - bitmap_device2.GetBitmap()->Clear(0); -#endif - CalculateDrawImage(&bitmap_device1, &bitmap_device2, m_Loader.GetMask(), + } + CalculateDrawImage(&bitmap_device1, &bitmap_device2, m_pLoader->GetMask(), new_matrix, rect); -#ifdef _SKIA_SUPPORT_ - m_pRenderStatus->GetRenderDevice()->SetBitsWithMask( - bitmap_device1.GetBitmap(), bitmap_device2.GetBitmap(), rect.left, - rect.top, m_BitmapAlpha, m_BlendType); -#else - bitmap_device2.GetBitmap()->ConvertFormat(FXDIB_8bppMask); +#if defined(_SKIA_SUPPORT_) + if (CFX_DefaultRenderDevice::SkiaIsDefaultRenderer()) { + m_pRenderStatus->GetRenderDevice()->SetBitsWithMask( + bitmap_device1.GetBitmap(), bitmap_device2.GetBitmap(), rect.left, + rect.top, m_BitmapAlpha, m_BlendType); + return false; + } +#endif + bitmap_device2.GetBitmap()->ConvertFormat(FXDIB_Format::k8bppMask); bitmap_device1.GetBitmap()->MultiplyAlpha(bitmap_device2.GetBitmap()); if (m_BitmapAlpha < 255) bitmap_device1.GetBitmap()->MultiplyAlpha(m_BitmapAlpha); m_pRenderStatus->GetRenderDevice()->SetDIBitsWithBlend( bitmap_device1.GetBitmap(), rect.left, rect.top, m_BlendType); -#endif // _SKIA_SUPPORT_ return false; } @@ -388,30 +412,16 @@ m_ResampleOptions.bInterpolateBilinear = true; } } -#ifdef _SKIA_SUPPORT_ - RetainPtr<CFX_DIBitmap> premultiplied = m_pDIBBase->Clone(nullptr); - if (m_pDIBBase->HasAlpha()) - CFX_SkiaDeviceDriver::PreMultiply(premultiplied); + RetainPtr<CFX_DIBBase> bitmap = PreMultiplyBitmapIfAlpha(m_pDIBBase); if (m_pRenderStatus->GetRenderDevice()->StartDIBitsWithBlend( - premultiplied, m_BitmapAlpha, m_FillArgb, m_ImageMatrix, - m_ResampleOptions, &m_DeviceHandle, m_BlendType)) { + bitmap, m_BitmapAlpha, m_FillArgb, m_ImageMatrix, m_ResampleOptions, + &m_DeviceHandle, m_BlendType)) { if (m_DeviceHandle) { m_Mode = Mode::kBlend; return true; } return false; } -#else - if (m_pRenderStatus->GetRenderDevice()->StartDIBitsWithBlend( - m_pDIBBase, m_BitmapAlpha, m_FillArgb, m_ImageMatrix, - m_ResampleOptions, &m_DeviceHandle, m_BlendType)) { - if (m_DeviceHandle) { - m_Mode = Mode::kBlend; - return true; - } - return false; - } -#endif if ((fabs(m_ImageMatrix.b) >= 0.5f || m_ImageMatrix.a == 0) || (fabs(m_ImageMatrix.c) >= 0.5f || m_ImageMatrix.d == 0)) { @@ -420,19 +430,19 @@ return false; } - Optional<FX_RECT> image_rect = GetUnitRect(); + absl::optional<FX_RECT> image_rect = GetUnitRect(); if (!image_rect.has_value()) return false; FX_RECT clip_box = m_pRenderStatus->GetRenderDevice()->GetClipBox(); clip_box.Intersect(image_rect.value()); m_Mode = Mode::kTransform; - m_pTransformer = pdfium::MakeUnique<CFX_ImageTransformer>( + m_pTransformer = std::make_unique<CFX_ImageTransformer>( m_pDIBBase, m_ImageMatrix, m_ResampleOptions, &clip_box); return true; } - Optional<FX_RECT> image_rect = GetUnitRect(); + absl::optional<FX_RECT> image_rect = GetUnitRect(); if (!image_rect.has_value()) return false; @@ -452,7 +462,7 @@ return false; } } - if (m_pDIBBase->IsAlphaMask()) { + if (m_pDIBBase->IsMaskFormat()) { if (m_BitmapAlpha != 255) m_FillArgb = FXARGB_MUL_ALPHA(m_FillArgb, m_BitmapAlpha); if (m_pRenderStatus->GetRenderDevice()->StretchBitMaskWithFlags( @@ -484,17 +494,18 @@ bool CPDF_ImageRenderer::StartBitmapAlpha() { if (m_pDIBBase->IsOpaqueImage()) { - CFX_PathData path; + CFX_Path path; path.AppendRect(0, 0, 1, 1); path.Transform(m_ImageMatrix); uint32_t fill_color = ArgbEncode(0xff, m_BitmapAlpha, m_BitmapAlpha, m_BitmapAlpha); - m_pRenderStatus->GetRenderDevice()->DrawPath(&path, nullptr, nullptr, - fill_color, 0, FXFILL_WINDING); + m_pRenderStatus->GetRenderDevice()->DrawPath( + path, nullptr, nullptr, fill_color, 0, + CFX_FillRenderOptions::WindingOptions()); return false; } RetainPtr<CFX_DIBBase> pAlphaMask; - if (m_pDIBBase->IsAlphaMask()) + if (m_pDIBBase->IsMaskFormat()) pAlphaMask = m_pDIBBase; else pAlphaMask = m_pDIBBase->CloneAlphaMask(); @@ -513,7 +524,7 @@ return false; } - Optional<FX_RECT> image_rect = GetUnitRect(); + absl::optional<FX_RECT> image_rect = GetUnitRect(); if (!image_rect.has_value()) return false; @@ -543,12 +554,10 @@ case Mode::kTransform: return ContinueTransform(pPause); } - NOTREACHED(); - return false; } bool CPDF_ImageRenderer::ContinueDefault(PauseIndicatorIface* pPause) { - if (m_Loader.Continue(pPause, m_pRenderStatus.Get())) + if (m_pLoader->Continue(pPause)) return true; if (!StartRenderDIBBase()) @@ -573,7 +582,7 @@ if (!pBitmap) return false; - if (pBitmap->IsAlphaMask()) { + if (pBitmap->IsMaskFormat()) { if (m_BitmapAlpha != 255) m_FillArgb = FXARGB_MUL_ALPHA(m_FillArgb, m_BitmapAlpha); m_Result = m_pRenderStatus->GetRenderDevice()->SetBitMask( @@ -590,37 +599,24 @@ } void CPDF_ImageRenderer::HandleFilters() { - CPDF_Object* pFilters = - m_pImageObject->GetImage()->GetStream()->GetDict()->GetDirectObjectFor( - "Filter"); - if (!pFilters) + absl::optional<DecoderArray> decoder_array = + GetDecoderArray(m_pImageObject->GetImage()->GetStream()->GetDict()); + if (!decoder_array.has_value()) return; - if (pFilters->IsName()) { - ByteString bsDecodeType = pFilters->GetString(); - if (bsDecodeType == "DCTDecode" || bsDecodeType == "JPXDecode") + for (const auto& decoder : decoder_array.value()) { + if (decoder.first == "DCTDecode" || decoder.first == "JPXDecode") { m_ResampleOptions.bLossy = true; - return; - } - - CPDF_Array* pArray = pFilters->AsArray(); - if (!pArray) - return; - - for (size_t i = 0; i < pArray->size(); i++) { - ByteString bsDecodeType = pArray->GetStringAt(i); - if (bsDecodeType == "DCTDecode" || bsDecodeType == "JPXDecode") { - m_ResampleOptions.bLossy = true; - break; + return; } } } -Optional<FX_RECT> CPDF_ImageRenderer::GetUnitRect() const { +absl::optional<FX_RECT> CPDF_ImageRenderer::GetUnitRect() const { CFX_FloatRect image_rect_f = m_ImageMatrix.GetUnitRect(); FX_RECT image_rect = image_rect_f.GetOuterRect(); if (!image_rect.Valid()) - return {}; + return absl::nullopt; return image_rect; } @@ -629,7 +625,7 @@ int* top, int* width, int* height) const { - ASSERT(rect.Valid()); + DCHECK(rect.Valid()); int dest_width = rect.Width(); int dest_height = rect.Height();
diff --git a/core/fpdfapi/render/cpdf_imagerenderer.h b/core/fpdfapi/render/cpdf_imagerenderer.h index d7c7bf0..530ac95 100644 --- a/core/fpdfapi/render/cpdf_imagerenderer.h +++ b/core/fpdfapi/render/cpdf_imagerenderer.h
@@ -1,4 +1,4 @@ -// Copyright 2016 PDFium Authors. All rights reserved. +// Copyright 2016 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -9,42 +9,37 @@ #include <memory> -#include "core/fpdfapi/render/cpdf_imageloader.h" #include "core/fxcrt/fx_coordinates.h" +#include "core/fxcrt/retain_ptr.h" #include "core/fxcrt/unowned_ptr.h" #include "core/fxge/dib/cfx_imagerenderer.h" -#include "core/fxge/fx_dib.h" -#include "third_party/base/optional.h" +#include "core/fxge/dib/fx_dib.h" +#include "third_party/abseil-cpp/absl/types/optional.h" -class CFX_DIBitmap; class CFX_DIBBase; class CFX_DefaultRenderDevice; class CFX_ImageTransformer; +class CPDF_ImageLoader; class CPDF_ImageObject; -class CPDF_PageObject; class CPDF_Pattern; class CPDF_RenderOptions; class CPDF_RenderStatus; class CPDF_ImageRenderer { public: - CPDF_ImageRenderer(); + explicit CPDF_ImageRenderer(CPDF_RenderStatus* pStatus); ~CPDF_ImageRenderer(); - bool Start(CPDF_RenderStatus* pStatus, - CPDF_ImageObject* pImageObject, + bool Start(CPDF_ImageObject* pImageObject, const CFX_Matrix& mtObj2Device, bool bStdCS, BlendMode blendType); - bool Start(CPDF_RenderStatus* pStatus, - const RetainPtr<CFX_DIBBase>& pDIBBase, + bool Start(RetainPtr<CFX_DIBBase> pDIBBase, FX_ARGB bitmap_argb, - int bitmap_alpha, const CFX_Matrix& mtImage2Device, const FXDIB_ResampleOptions& options, - bool bStdCS, - BlendMode blendType); + bool bStdCS); bool Continue(PauseIndicatorIface* pPause); bool GetResult() const { return m_Result; } @@ -71,25 +66,25 @@ CFX_Matrix GetDrawMatrix(const FX_RECT& rect) const; void CalculateDrawImage(CFX_DefaultRenderDevice* pBitmapDevice1, CFX_DefaultRenderDevice* pBitmapDevice2, - const RetainPtr<CFX_DIBBase>& pDIBBase, + RetainPtr<CFX_DIBBase> pDIBBase, const CFX_Matrix& mtNewMatrix, const FX_RECT& rect) const; const CPDF_RenderOptions& GetRenderOptions() const; void HandleFilters(); - Optional<FX_RECT> GetUnitRect() const; + absl::optional<FX_RECT> GetUnitRect() const; bool GetDimensionsFromUnitRect(const FX_RECT& rect, int* left, int* top, int* width, int* height) const; - UnownedPtr<CPDF_RenderStatus> m_pRenderStatus; + UnownedPtr<CPDF_RenderStatus> const m_pRenderStatus; UnownedPtr<CPDF_ImageObject> m_pImageObject; RetainPtr<CPDF_Pattern> m_pPattern; RetainPtr<CFX_DIBBase> m_pDIBBase; CFX_Matrix m_mtObj2Device; CFX_Matrix m_ImageMatrix; - CPDF_ImageLoader m_Loader; + std::unique_ptr<CPDF_ImageLoader> const m_pLoader; std::unique_ptr<CFX_ImageTransformer> m_pTransformer; std::unique_ptr<CFX_ImageRenderer> m_DeviceHandle; Mode m_Mode = Mode::kNone;
diff --git a/core/fpdfapi/render/cpdf_pagerendercache.cpp b/core/fpdfapi/render/cpdf_pagerendercache.cpp deleted file mode 100644 index ca4f8ee..0000000 --- a/core/fpdfapi/render/cpdf_pagerendercache.cpp +++ /dev/null
@@ -1,133 +0,0 @@ -// Copyright 2016 PDFium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com - -#include "core/fpdfapi/render/cpdf_pagerendercache.h" - -#include <algorithm> -#include <vector> - -#include "core/fpdfapi/page/cpdf_image.h" -#include "core/fpdfapi/page/cpdf_page.h" -#include "core/fpdfapi/render/cpdf_imagecacheentry.h" -#include "core/fpdfapi/render/cpdf_renderstatus.h" -#include "core/fxge/dib/cfx_dibitmap.h" -#include "third_party/base/ptr_util.h" - -namespace { - -struct CacheInfo { - CacheInfo(uint32_t t, CPDF_Stream* stream) : time(t), pStream(stream) {} - - uint32_t time; - CPDF_Stream* pStream; - - bool operator<(const CacheInfo& other) const { return time < other.time; } -}; - -} // namespace - -CPDF_PageRenderCache::CPDF_PageRenderCache(CPDF_Page* pPage) : m_pPage(pPage) {} - -CPDF_PageRenderCache::~CPDF_PageRenderCache() = default; - -void CPDF_PageRenderCache::CacheOptimization(int32_t dwLimitCacheSize) { - if (m_nCacheSize <= (uint32_t)dwLimitCacheSize) - return; - - size_t nCount = m_ImageCache.size(); - std::vector<CacheInfo> cache_info; - cache_info.reserve(nCount); - for (const auto& it : m_ImageCache) { - cache_info.emplace_back(it.second->GetTimeCount(), - it.second->GetImage()->GetStream()); - } - std::sort(cache_info.begin(), cache_info.end()); - - // Check if time value is about to roll over and reset all entries. - // The comparision is legal because uint32_t is an unsigned type. - uint32_t nTimeCount = m_nTimeCount; - if (nTimeCount + 1 < nTimeCount) { - for (size_t i = 0; i < nCount; i++) - m_ImageCache[cache_info[i].pStream]->m_dwTimeCount = i; - m_nTimeCount = nCount; - } - - size_t i = 0; - while (i + 15 < nCount) - ClearImageCacheEntry(cache_info[i++].pStream); - - while (i < nCount && m_nCacheSize > (uint32_t)dwLimitCacheSize) - ClearImageCacheEntry(cache_info[i++].pStream); -} - -void CPDF_PageRenderCache::ClearImageCacheEntry(CPDF_Stream* pStream) { - auto it = m_ImageCache.find(pStream); - if (it == m_ImageCache.end()) - return; - - m_nCacheSize -= it->second->EstimateSize(); - m_ImageCache.erase(it); -} - -bool CPDF_PageRenderCache::StartGetCachedBitmap( - const RetainPtr<CPDF_Image>& pImage, - bool bStdCS, - uint32_t GroupFamily, - bool bLoadMask, - CPDF_RenderStatus* pRenderStatus) { - CPDF_Stream* pStream = pImage->GetStream(); - const auto it = m_ImageCache.find(pStream); - m_bCurFindCache = it != m_ImageCache.end(); - if (m_bCurFindCache) { - m_pCurImageCacheEntry = it->second.get(); - } else { - m_pCurImageCacheEntry = pdfium::MakeUnique<CPDF_ImageCacheEntry>( - m_pPage->GetDocument(), pImage); - } - CPDF_DIB::LoadState ret = m_pCurImageCacheEntry->StartGetCachedBitmap( - pRenderStatus->GetFormResource(), m_pPage->m_pPageResources.Get(), bStdCS, - GroupFamily, bLoadMask, pRenderStatus); - if (ret == CPDF_DIB::LoadState::kContinue) - return true; - - m_nTimeCount++; - if (!m_bCurFindCache) - m_ImageCache[pStream] = m_pCurImageCacheEntry.Release(); - - if (ret == CPDF_DIB::LoadState::kFail) - m_nCacheSize += m_pCurImageCacheEntry->EstimateSize(); - - return false; -} - -bool CPDF_PageRenderCache::Continue(PauseIndicatorIface* pPause, - CPDF_RenderStatus* pRenderStatus) { - bool ret = m_pCurImageCacheEntry->Continue(pPause, pRenderStatus); - if (ret) - return true; - - m_nTimeCount++; - if (!m_bCurFindCache) { - m_ImageCache[m_pCurImageCacheEntry->GetImage()->GetStream()] = - m_pCurImageCacheEntry.Release(); - } - m_nCacheSize += m_pCurImageCacheEntry->EstimateSize(); - return false; -} - -void CPDF_PageRenderCache::ResetBitmapForImage( - const RetainPtr<CPDF_Image>& pImage) { - CPDF_ImageCacheEntry* pEntry; - CPDF_Stream* pStream = pImage->GetStream(); - const auto it = m_ImageCache.find(pStream); - if (it == m_ImageCache.end()) - return; - - pEntry = it->second.get(); - m_nCacheSize -= pEntry->EstimateSize(); - pEntry->Reset(); - m_nCacheSize += pEntry->EstimateSize(); -}
diff --git a/core/fpdfapi/render/cpdf_pagerendercache.h b/core/fpdfapi/render/cpdf_pagerendercache.h deleted file mode 100644 index 1fb2a61..0000000 --- a/core/fpdfapi/render/cpdf_pagerendercache.h +++ /dev/null
@@ -1,60 +0,0 @@ -// Copyright 2016 PDFium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com - -#ifndef CORE_FPDFAPI_RENDER_CPDF_PAGERENDERCACHE_H_ -#define CORE_FPDFAPI_RENDER_CPDF_PAGERENDERCACHE_H_ - -#include <map> -#include <memory> - -#include "core/fpdfapi/page/cpdf_page.h" -#include "core/fxcrt/fx_system.h" -#include "core/fxcrt/maybe_owned.h" -#include "core/fxcrt/retain_ptr.h" -#include "core/fxcrt/unowned_ptr.h" - -class CPDF_Image; -class CPDF_ImageCacheEntry; -class CPDF_Page; -class CPDF_RenderStatus; -class CPDF_Stream; -class PauseIndicatorIface; - -class CPDF_PageRenderCache : public CPDF_Page::RenderCacheIface { - public: - explicit CPDF_PageRenderCache(CPDF_Page* pPage); - ~CPDF_PageRenderCache() override; - - // CPDF_Page::RenderCacheIface: - void ResetBitmapForImage(const RetainPtr<CPDF_Image>& pImage) override; - - void CacheOptimization(int32_t dwLimitCacheSize); - uint32_t GetTimeCount() const { return m_nTimeCount; } - CPDF_Page* GetPage() const { return m_pPage.Get(); } - CPDF_ImageCacheEntry* GetCurImageCacheEntry() const { - return m_pCurImageCacheEntry.Get(); - } - - bool StartGetCachedBitmap(const RetainPtr<CPDF_Image>& pImage, - bool bStdCS, - uint32_t GroupFamily, - bool bLoadMask, - CPDF_RenderStatus* pRenderStatus); - - bool Continue(PauseIndicatorIface* pPause, CPDF_RenderStatus* pRenderStatus); - - private: - void ClearImageCacheEntry(CPDF_Stream* pStream); - - UnownedPtr<CPDF_Page> const m_pPage; - std::map<CPDF_Stream*, std::unique_ptr<CPDF_ImageCacheEntry>> m_ImageCache; - MaybeOwned<CPDF_ImageCacheEntry> m_pCurImageCacheEntry; - uint32_t m_nTimeCount = 0; - uint32_t m_nCacheSize = 0; - bool m_bCurFindCache = false; -}; - -#endif // CORE_FPDFAPI_RENDER_CPDF_PAGERENDERCACHE_H_
diff --git a/core/fpdfapi/render/cpdf_pagerendercontext.cpp b/core/fpdfapi/render/cpdf_pagerendercontext.cpp index 8dd66c7..9899041 100644 --- a/core/fpdfapi/render/cpdf_pagerendercontext.cpp +++ b/core/fpdfapi/render/cpdf_pagerendercontext.cpp
@@ -1,4 +1,4 @@ -// Copyright 2016 PDFium Authors. All rights reserved. +// Copyright 2016 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -12,6 +12,6 @@ #include "core/fpdfapi/render/cpdf_renderoptions.h" #include "core/fxge/cfx_renderdevice.h" -CPDF_PageRenderContext::CPDF_PageRenderContext() {} +CPDF_PageRenderContext::CPDF_PageRenderContext() = default; -CPDF_PageRenderContext::~CPDF_PageRenderContext() {} +CPDF_PageRenderContext::~CPDF_PageRenderContext() = default;
diff --git a/core/fpdfapi/render/cpdf_pagerendercontext.h b/core/fpdfapi/render/cpdf_pagerendercontext.h index 8a5a5eb..f6366c4 100644 --- a/core/fpdfapi/render/cpdf_pagerendercontext.h +++ b/core/fpdfapi/render/cpdf_pagerendercontext.h
@@ -1,4 +1,4 @@ -// Copyright 2016 PDFium Authors. All rights reserved. +// Copyright 2016 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -22,7 +22,7 @@ // Context merely manages the lifetime for callers. class AnnotListIface { public: - virtual ~AnnotListIface() {} + virtual ~AnnotListIface() = default; }; CPDF_PageRenderContext();
diff --git a/core/fpdfapi/render/cpdf_progressiverenderer.cpp b/core/fpdfapi/render/cpdf_progressiverenderer.cpp index 6e5fc36..c29077a 100644 --- a/core/fpdfapi/render/cpdf_progressiverenderer.cpp +++ b/core/fpdfapi/render/cpdf_progressiverenderer.cpp
@@ -1,4 +1,4 @@ -// Copyright 2016 PDFium Authors. All rights reserved. +// Copyright 2016 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -8,14 +8,13 @@ #include "core/fpdfapi/page/cpdf_image.h" #include "core/fpdfapi/page/cpdf_imageobject.h" +#include "core/fpdfapi/page/cpdf_pageimagecache.h" #include "core/fpdfapi/page/cpdf_pageobject.h" #include "core/fpdfapi/page/cpdf_pageobjectholder.h" -#include "core/fpdfapi/render/cpdf_pagerendercache.h" #include "core/fpdfapi/render/cpdf_renderoptions.h" #include "core/fpdfapi/render/cpdf_renderstatus.h" #include "core/fxcrt/pauseindicator_iface.h" #include "core/fxge/cfx_renderdevice.h" -#include "third_party/base/ptr_util.h" CPDF_ProgressiveRenderer::CPDF_ProgressiveRenderer( CPDF_RenderContext* pContext, @@ -47,26 +46,26 @@ return; } m_pCurrentLayer = m_pContext->GetLayer(m_LayerIndex); - m_LastObjectRendered = m_pCurrentLayer->m_pObjectHolder->end(); - m_pRenderStatus = pdfium::MakeUnique<CPDF_RenderStatus>(m_pContext.Get(), - m_pDevice.Get()); + m_LastObjectRendered = m_pCurrentLayer->GetObjectHolder()->end(); + m_pRenderStatus = + std::make_unique<CPDF_RenderStatus>(m_pContext, m_pDevice); if (m_pOptions) m_pRenderStatus->SetOptions(*m_pOptions); m_pRenderStatus->SetTransparency( - m_pCurrentLayer->m_pObjectHolder->GetTransparency()); + m_pCurrentLayer->GetObjectHolder()->GetTransparency()); m_pRenderStatus->Initialize(nullptr, nullptr); m_pDevice->SaveState(); - m_ClipRect = m_pCurrentLayer->m_Matrix.GetInverse().TransformRect( + m_ClipRect = m_pCurrentLayer->GetMatrix().GetInverse().TransformRect( CFX_FloatRect(m_pDevice->GetClipBox())); } CPDF_PageObjectHolder::const_iterator iter; CPDF_PageObjectHolder::const_iterator iterEnd = - m_pCurrentLayer->m_pObjectHolder->end(); + m_pCurrentLayer->GetObjectHolder()->end(); if (m_LastObjectRendered != iterEnd) { iter = m_LastObjectRendered; ++iter; } else { - iter = m_pCurrentLayer->m_pObjectHolder->begin(); + iter = m_pCurrentLayer->GetObjectHolder()->begin(); } int nObjsToGo = kStepLimit; bool is_mask = false; @@ -81,13 +80,13 @@ if (m_pDevice->GetDeviceType() == DeviceType::kPrinter) { m_LastObjectRendered = iter; m_pRenderStatus->ProcessClipPath(pCurObj->m_ClipPath, - m_pCurrentLayer->m_Matrix); + m_pCurrentLayer->GetMatrix()); return; } is_mask = true; } if (m_pRenderStatus->ContinueSingleObject( - pCurObj, m_pCurrentLayer->m_Matrix, pPause)) { + pCurObj, m_pCurrentLayer->GetMatrix(), pPause)) { return; } if (pCurObj->IsImage() && m_pRenderStatus->GetRenderOptions() @@ -111,7 +110,7 @@ if (is_mask && iter != iterEnd) return; } - if (m_pCurrentLayer->m_pObjectHolder->GetParseState() == + if (m_pCurrentLayer->GetObjectHolder()->GetParseState() == CPDF_PageObjectHolder::ParseState::kParsed) { m_pRenderStatus.reset(); m_pDevice->RestoreState(false); @@ -122,8 +121,8 @@ } else if (is_mask) { return; } else { - m_pCurrentLayer->m_pObjectHolder->ContinueParse(pPause); - if (m_pCurrentLayer->m_pObjectHolder->GetParseState() != + m_pCurrentLayer->GetObjectHolder()->ContinueParse(pPause); + if (m_pCurrentLayer->GetObjectHolder()->GetParseState() != CPDF_PageObjectHolder::ParseState::kParsed) { return; }
diff --git a/core/fpdfapi/render/cpdf_progressiverenderer.h b/core/fpdfapi/render/cpdf_progressiverenderer.h index fd399f9..67170fc 100644 --- a/core/fpdfapi/render/cpdf_progressiverenderer.h +++ b/core/fpdfapi/render/cpdf_progressiverenderer.h
@@ -1,4 +1,4 @@ -// Copyright 2016 PDFium Authors. All rights reserved. +// Copyright 2016 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -7,12 +7,14 @@ #ifndef CORE_FPDFAPI_RENDER_CPDF_PROGRESSIVERENDERER_H_ #define CORE_FPDFAPI_RENDER_CPDF_PROGRESSIVERENDERER_H_ +#include <stdint.h> + #include <memory> #include "core/fpdfapi/page/cpdf_pageobjectholder.h" #include "core/fpdfapi/render/cpdf_rendercontext.h" #include "core/fxcrt/fx_coordinates.h" -#include "core/fxcrt/fx_system.h" +#include "core/fxcrt/unowned_ptr.h" class CPDF_RenderOptions; class CPDF_RenderStatus; @@ -42,12 +44,12 @@ private: // Maximum page objects to render before checking for pause. - static const int kStepLimit = 100; + static constexpr int kStepLimit = 100; Status m_Status = kReady; UnownedPtr<CPDF_RenderContext> const m_pContext; UnownedPtr<CFX_RenderDevice> const m_pDevice; - const CPDF_RenderOptions* const m_pOptions; + UnownedPtr<const CPDF_RenderOptions> const m_pOptions; std::unique_ptr<CPDF_RenderStatus> m_pRenderStatus; CFX_FloatRect m_ClipRect; uint32_t m_LayerIndex = 0;
diff --git a/core/fpdfapi/render/cpdf_rendercontext.cpp b/core/fpdfapi/render/cpdf_rendercontext.cpp index 1280cee..4116840 100644 --- a/core/fpdfapi/render/cpdf_rendercontext.cpp +++ b/core/fpdfapi/render/cpdf_rendercontext.cpp
@@ -1,4 +1,4 @@ -// Copyright 2016 PDFium Authors. All rights reserved. +// Copyright 2016 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -6,11 +6,13 @@ #include "core/fpdfapi/render/cpdf_rendercontext.h" +#include <utility> + +#include "core/fpdfapi/page/cpdf_pageimagecache.h" #include "core/fpdfapi/page/cpdf_pageobject.h" #include "core/fpdfapi/page/cpdf_pageobjectholder.h" #include "core/fpdfapi/parser/cpdf_dictionary.h" #include "core/fpdfapi/parser/cpdf_document.h" -#include "core/fpdfapi/render/cpdf_pagerendercache.h" #include "core/fpdfapi/render/cpdf_progressiverenderer.h" #include "core/fpdfapi/render/cpdf_renderoptions.h" #include "core/fpdfapi/render/cpdf_renderstatus.h" @@ -18,41 +20,32 @@ #include "core/fxge/cfx_defaultrenderdevice.h" #include "core/fxge/cfx_renderdevice.h" #include "core/fxge/dib/cfx_dibitmap.h" -#include "core/fxge/fx_dib.h" +#include "core/fxge/dib/fx_dib.h" -CPDF_RenderContext::CPDF_RenderContext(CPDF_Document* pDoc, - CPDF_Dictionary* pPageResources, - CPDF_PageRenderCache* pPageCache) +CPDF_RenderContext::CPDF_RenderContext( + CPDF_Document* pDoc, + RetainPtr<CPDF_Dictionary> pPageResources, + CPDF_PageImageCache* pPageCache) : m_pDocument(pDoc), - m_pPageResources(pPageResources), + m_pPageResources(std::move(pPageResources)), m_pPageCache(pPageCache) {} CPDF_RenderContext::~CPDF_RenderContext() = default; -void CPDF_RenderContext::GetBackground(const RetainPtr<CFX_DIBitmap>& pBuffer, +void CPDF_RenderContext::GetBackground(RetainPtr<CFX_DIBitmap> pBuffer, const CPDF_PageObject* pObj, const CPDF_RenderOptions* pOptions, const CFX_Matrix& mtFinal) { CFX_DefaultRenderDevice device; - device.Attach(pBuffer, false, nullptr, false); - + device.Attach(std::move(pBuffer)); device.FillRect(FX_RECT(0, 0, device.GetWidth(), device.GetHeight()), 0xffffffff); Render(&device, pObj, pOptions, &mtFinal); } void CPDF_RenderContext::AppendLayer(CPDF_PageObjectHolder* pObjectHolder, - const CFX_Matrix* pObject2Device) { - m_Layers.emplace_back(); - m_Layers.back().m_pObjectHolder = pObjectHolder; - if (pObject2Device) - m_Layers.back().m_Matrix = *pObject2Device; -} - -void CPDF_RenderContext::Render(CFX_RenderDevice* pDevice, - const CPDF_RenderOptions* pOptions, - const CFX_Matrix* pLastMatrix) { - Render(pDevice, nullptr, pOptions, pLastMatrix); + const CFX_Matrix& mtObject2Device) { + m_Layers.emplace_back(pObjectHolder, mtObject2Device); } void CPDF_RenderContext::Render(CFX_RenderDevice* pDevice, @@ -65,14 +58,14 @@ if (pOptions) status.SetOptions(*pOptions); status.SetStopObject(pStopObj); - status.SetTransparency(layer.m_pObjectHolder->GetTransparency()); - CFX_Matrix final_matrix = layer.m_Matrix; + status.SetTransparency(layer.GetObjectHolder()->GetTransparency()); + CFX_Matrix final_matrix = layer.GetMatrix(); if (pLastMatrix) { final_matrix *= *pLastMatrix; status.SetDeviceMatrix(*pLastMatrix); } status.Initialize(nullptr, nullptr); - status.RenderObjectList(layer.m_pObjectHolder.Get(), final_matrix); + status.RenderObjectList(layer.GetObjectHolder(), final_matrix); if (status.GetRenderOptions().GetOptions().bLimitedImageCache) { m_pPageCache->CacheOptimization( status.GetRenderOptions().GetCacheSizeLimit()); @@ -82,7 +75,9 @@ } } -CPDF_RenderContext::Layer::Layer() = default; +CPDF_RenderContext::Layer::Layer(CPDF_PageObjectHolder* pHolder, + const CFX_Matrix& matrix) + : m_pObjectHolder(pHolder), m_Matrix(matrix) {} CPDF_RenderContext::Layer::Layer(const Layer& that) = default;
diff --git a/core/fpdfapi/render/cpdf_rendercontext.h b/core/fpdfapi/render/cpdf_rendercontext.h index d9efbc4..383e798 100644 --- a/core/fpdfapi/render/cpdf_rendercontext.h +++ b/core/fpdfapi/render/cpdf_rendercontext.h
@@ -1,4 +1,4 @@ -// Copyright 2016 PDFium Authors. All rights reserved. +// Copyright 2016 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -13,46 +13,46 @@ #include "core/fxcrt/retain_ptr.h" #include "core/fxcrt/unowned_ptr.h" -class CPDF_Dictionary; -class CPDF_Document; -class CPDF_PageObject; -class CPDF_PageObjectHolder; -class CPDF_PageRenderCache; -class CPDF_RenderOptions; class CFX_DIBitmap; class CFX_Matrix; class CFX_RenderDevice; +class CPDF_Dictionary; +class CPDF_Document; +class CPDF_PageImageCache; +class CPDF_PageObject; +class CPDF_PageObjectHolder; +class CPDF_RenderOptions; class CPDF_RenderContext { public: class Layer { public: - Layer(); + Layer(CPDF_PageObjectHolder* pHolder, const CFX_Matrix& matrix); Layer(const Layer& that); ~Layer(); - UnownedPtr<CPDF_PageObjectHolder> m_pObjectHolder; - CFX_Matrix m_Matrix; + CPDF_PageObjectHolder* GetObjectHolder() { return m_pObjectHolder; } + const CFX_Matrix& GetMatrix() const { return m_Matrix; } + + private: + UnownedPtr<CPDF_PageObjectHolder> const m_pObjectHolder; + const CFX_Matrix m_Matrix; }; CPDF_RenderContext(CPDF_Document* pDoc, - CPDF_Dictionary* pPageResources, - CPDF_PageRenderCache* pPageCache); + RetainPtr<CPDF_Dictionary> pPageResources, + CPDF_PageImageCache* pPageCache); ~CPDF_RenderContext(); void AppendLayer(CPDF_PageObjectHolder* pObjectHolder, - const CFX_Matrix* pObject2Device); - - void Render(CFX_RenderDevice* pDevice, - const CPDF_RenderOptions* pOptions, - const CFX_Matrix* pLastMatrix); + const CFX_Matrix& mtObject2Device); void Render(CFX_RenderDevice* pDevice, const CPDF_PageObject* pStopObj, const CPDF_RenderOptions* pOptions, const CFX_Matrix* pLastMatrix); - void GetBackground(const RetainPtr<CFX_DIBitmap>& pBuffer, + void GetBackground(RetainPtr<CFX_DIBitmap> pBuffer, const CPDF_PageObject* pObj, const CPDF_RenderOptions* pOptions, const CFX_Matrix& mtFinal); @@ -60,14 +60,19 @@ size_t CountLayers() const { return m_Layers.size(); } Layer* GetLayer(uint32_t index) { return &m_Layers[index]; } - CPDF_Document* GetDocument() const { return m_pDocument.Get(); } - CPDF_Dictionary* GetPageResources() const { return m_pPageResources.Get(); } - CPDF_PageRenderCache* GetPageCache() const { return m_pPageCache.Get(); } + CPDF_Document* GetDocument() const { return m_pDocument; } + const CPDF_Dictionary* GetPageResources() const { + return m_pPageResources.Get(); + } + RetainPtr<CPDF_Dictionary> GetMutablePageResources() { + return m_pPageResources; + } + CPDF_PageImageCache* GetPageCache() const { return m_pPageCache; } - protected: + private: UnownedPtr<CPDF_Document> const m_pDocument; RetainPtr<CPDF_Dictionary> const m_pPageResources; - UnownedPtr<CPDF_PageRenderCache> const m_pPageCache; + UnownedPtr<CPDF_PageImageCache> const m_pPageCache; std::vector<Layer> m_Layers; };
diff --git a/core/fpdfapi/render/cpdf_renderoptions.cpp b/core/fpdfapi/render/cpdf_renderoptions.cpp index 11efe9e..68bb472 100644 --- a/core/fpdfapi/render/cpdf_renderoptions.cpp +++ b/core/fpdfapi/render/cpdf_renderoptions.cpp
@@ -1,4 +1,4 @@ -// Copyright 2016 PDFium Authors. All rights reserved. +// Copyright 2016 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -17,6 +17,9 @@ CPDF_RenderOptions::Options::Options(const CPDF_RenderOptions::Options& rhs) = default; +CPDF_RenderOptions::Options& CPDF_RenderOptions::Options::operator=( + const CPDF_RenderOptions::Options& rhs) = default; + CPDF_RenderOptions::CPDF_RenderOptions() { // TODO(thestig): Make constexpr to initialize |m_Options| once C++14 is // available. @@ -42,6 +45,34 @@ return ArgbEncode(a, gray, gray, gray); } +FX_ARGB CPDF_RenderOptions::TranslateObjectColor( + FX_ARGB argb, + CPDF_PageObject::Type object_type, + RenderType render_type) const { + if (!ColorModeIs(kForcedColor)) + return TranslateColor(argb); + + switch (object_type) { + case CPDF_PageObject::Type::kPath: + return render_type == RenderType::kFill ? m_ColorScheme.path_fill_color + : m_ColorScheme.path_stroke_color; + case CPDF_PageObject::Type::kText: + return render_type == RenderType::kFill ? m_ColorScheme.text_fill_color + : m_ColorScheme.text_stroke_color; + default: + return argb; + } +} + uint32_t CPDF_RenderOptions::GetCacheSizeLimit() const { return kCacheSizeLimitBytes; } + +bool CPDF_RenderOptions::CheckOCGDictVisible(const CPDF_Dictionary* pOC) const { + return !m_pOCContext || m_pOCContext->CheckOCGDictVisible(pOC); +} + +bool CPDF_RenderOptions::CheckPageObjectVisible( + const CPDF_PageObject* pPageObj) const { + return !m_pOCContext || m_pOCContext->CheckPageObjectVisible(pPageObj); +}
diff --git a/core/fpdfapi/render/cpdf_renderoptions.h b/core/fpdfapi/render/cpdf_renderoptions.h index 84f7e4c..12eb91a 100644 --- a/core/fpdfapi/render/cpdf_renderoptions.h +++ b/core/fpdfapi/render/cpdf_renderoptions.h
@@ -1,4 +1,4 @@ -// Copyright 2016 PDFium Authors. All rights reserved. +// Copyright 2016 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -7,35 +7,43 @@ #ifndef CORE_FPDFAPI_RENDER_CPDF_RENDEROPTIONS_H_ #define CORE_FPDFAPI_RENDER_CPDF_RENDEROPTIONS_H_ +#include <stdint.h> + #include "core/fpdfapi/page/cpdf_occontext.h" -#include "core/fxcrt/fx_system.h" +#include "core/fpdfapi/page/cpdf_pageobject.h" #include "core/fxcrt/retain_ptr.h" -#include "core/fxge/fx_dib.h" +#include "core/fxge/dib/fx_dib.h" + +class CPDF_Dictionary; class CPDF_RenderOptions { public: - enum Type : uint8_t { kNormal = 0, kGray, kAlpha }; + enum Type : uint8_t { kNormal = 0, kGray, kAlpha, kForcedColor }; + + enum RenderType : uint8_t { kFill = 0, kStroke }; struct Options { Options(); Options(const Options& rhs); + Options& operator=(const Options& rhs); bool bClearType = false; - bool bPrintGraphicText = false; - bool bPrintPreview = false; - bool bBGRStripe = false; bool bNoNativeText = false; bool bForceHalftone = false; bool bRectAA = false; - bool bFillFullcover = false; - bool bPrintImageText = false; - bool bOverprint = false; - bool bThinLine = false; bool bBreakForMasks = false; bool bNoTextSmooth = false; bool bNoPathSmooth = false; bool bNoImageSmooth = false; bool bLimitedImageCache = false; + bool bConvertFillToStroke = false; + }; + + struct ColorScheme { + FX_ARGB path_fill_color; + FX_ARGB path_stroke_color; + FX_ARGB text_fill_color; + FX_ARGB text_stroke_color; }; CPDF_RenderOptions(); @@ -43,6 +51,13 @@ ~CPDF_RenderOptions(); FX_ARGB TranslateColor(FX_ARGB argb) const; + FX_ARGB TranslateObjectColor(FX_ARGB argb, + CPDF_PageObject::Type object_type, + RenderType render_type) const; + + void SetColorScheme(const ColorScheme& color_scheme) { + m_ColorScheme = color_scheme; + } void SetColorMode(Type mode) { m_ColorMode = mode; } bool ColorModeIs(Type mode) const { return m_ColorMode == mode; } @@ -51,6 +66,8 @@ Options& GetOptions() { return m_Options; } uint32_t GetCacheSizeLimit() const; + bool CheckOCGDictVisible(const CPDF_Dictionary* pOC) const; + bool CheckPageObjectVisible(const CPDF_PageObject* pPageObj) const; void SetDrawAnnots(bool draw) { m_bDrawAnnots = draw; } bool GetDrawAnnots() const { return m_bDrawAnnots; } @@ -58,12 +75,12 @@ void SetOCContext(RetainPtr<CPDF_OCContext> context) { m_pOCContext = context; } - const CPDF_OCContext* GetOCContext() const { return m_pOCContext.Get(); } private: Type m_ColorMode = kNormal; bool m_bDrawAnnots = false; Options m_Options; + ColorScheme m_ColorScheme = {}; RetainPtr<CPDF_OCContext> m_pOCContext; };
diff --git a/core/fpdfapi/render/cpdf_rendershading.cpp b/core/fpdfapi/render/cpdf_rendershading.cpp index 53fb79a..ce7543b 100644 --- a/core/fpdfapi/render/cpdf_rendershading.cpp +++ b/core/fpdfapi/render/cpdf_rendershading.cpp
@@ -1,4 +1,4 @@ -// Copyright 2019 PDFium Authors. All rights reserved. +// Copyright 2019 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -6,9 +6,10 @@ #include "core/fpdfapi/render/cpdf_rendershading.h" +#include <math.h> + #include <algorithm> #include <array> -#include <cmath> #include <memory> #include <utility> #include <vector> @@ -25,9 +26,16 @@ #include "core/fpdfapi/render/cpdf_renderoptions.h" #include "core/fxcrt/fx_safe_types.h" #include "core/fxcrt/fx_system.h" +#include "core/fxcrt/span_util.h" #include "core/fxge/cfx_defaultrenderdevice.h" +#include "core/fxge/cfx_fillrenderoptions.h" +#include "core/fxge/cfx_path.h" #include "core/fxge/dib/cfx_dibitmap.h" -#include "core/fxge/fx_dib.h" +#include "core/fxge/dib/fx_dib.h" +#include "third_party/base/check.h" +#include "third_party/base/check_op.h" +#include "third_party/base/cxx17_backports.h" +#include "third_party/base/span.h" namespace { @@ -57,28 +65,28 @@ const RetainPtr<CPDF_ColorSpace>& pCS, int alpha, size_t results_count) { - ASSERT(results_count >= CountOutputsFromFunctions(funcs)); - ASSERT(results_count >= pCS->CountComponents()); + DCHECK(results_count >= CountOutputsFromFunctions(funcs)); + DCHECK(results_count >= pCS->CountComponents()); std::array<FX_ARGB, kShadingSteps> shading_steps; std::vector<float> result_array(results_count); float diff = t_max - t_min; for (int i = 0; i < kShadingSteps; ++i) { float input = diff * i / kShadingSteps + t_min; - int offset = 0; + pdfium::span<float> result_span = pdfium::make_span(result_array); for (const auto& func : funcs) { - if (func) { - int nresults = 0; - if (func->Call(&input, 1, &result_array[offset], &nresults)) - offset += nresults; - } + if (!func) + continue; + absl::optional<uint32_t> nresults = + func->Call(pdfium::make_span(&input, 1), result_span); + if (nresults.has_value()) + result_span = result_span.subspan(nresults.value()); } float R = 0.0f; float G = 0.0f; float B = 0.0f; - pCS->GetRGB(result_array.data(), &R, &G, &B); - shading_steps[i] = - FXARGB_TODIB(ArgbEncode(alpha, FXSYS_roundf(R * 255), - FXSYS_roundf(G * 255), FXSYS_roundf(B * 255))); + pCS->GetRGB(result_array, &R, &G, &B); + shading_steps[i] = ArgbEncode(alpha, FXSYS_roundf(R * 255), + FXSYS_roundf(G * 255), FXSYS_roundf(B * 255)); } return shading_steps; } @@ -89,26 +97,26 @@ const std::vector<std::unique_ptr<CPDF_Function>>& funcs, const RetainPtr<CPDF_ColorSpace>& pCS, int alpha) { - ASSERT(pBitmap->GetFormat() == FXDIB_Argb); + DCHECK_EQ(pBitmap->GetFormat(), FXDIB_Format::kArgb); const uint32_t total_results = GetValidatedOutputsCount(funcs, pCS); if (total_results == 0) return; - const CPDF_Array* pCoords = pDict->GetArrayFor("Coords"); + RetainPtr<const CPDF_Array> pCoords = pDict->GetArrayFor("Coords"); if (!pCoords) return; - float start_x = pCoords->GetNumberAt(0); - float start_y = pCoords->GetNumberAt(1); - float end_x = pCoords->GetNumberAt(2); - float end_y = pCoords->GetNumberAt(3); + float start_x = pCoords->GetFloatAt(0); + float start_y = pCoords->GetFloatAt(1); + float end_x = pCoords->GetFloatAt(2); + float end_y = pCoords->GetFloatAt(3); float t_min = 0; float t_max = 1.0f; - const CPDF_Array* pArray = pDict->GetArrayFor("Domain"); + RetainPtr<const CPDF_Array> pArray = pDict->GetArrayFor("Domain"); if (pArray) { - t_min = pArray->GetNumberAt(0); - t_max = pArray->GetNumberAt(1); + t_min = pArray->GetFloatAt(0); + t_max = pArray->GetFloatAt(1); } pArray = pDict->GetArrayFor("Extend"); const bool bStartExtend = pArray && pArray->GetBooleanAt(0, false); @@ -123,18 +131,17 @@ std::array<FX_ARGB, kShadingSteps> shading_steps = GetShadingSteps(t_min, t_max, funcs, pCS, alpha, total_results); - int pitch = pBitmap->GetPitch(); CFX_Matrix matrix = mtObject2Bitmap.GetInverse(); for (int row = 0; row < height; row++) { uint32_t* dib_buf = - reinterpret_cast<uint32_t*>(pBitmap->GetBuffer() + row * pitch); + reinterpret_cast<uint32_t*>(pBitmap->GetWritableScanline(row).data()); for (int column = 0; column < width; column++) { CFX_PointF pos = matrix.Transform( CFX_PointF(static_cast<float>(column), static_cast<float>(row))); float scale = (((pos.x - start_x) * x_span) + ((pos.y - start_y) * y_span)) / axis_len_square; - int index = (int32_t)(scale * (kShadingSteps - 1)); + int index = static_cast<int32_t>(scale * (kShadingSteps - 1)); if (index < 0) { if (!bStartExtend) continue; @@ -157,28 +164,28 @@ const std::vector<std::unique_ptr<CPDF_Function>>& funcs, const RetainPtr<CPDF_ColorSpace>& pCS, int alpha) { - ASSERT(pBitmap->GetFormat() == FXDIB_Argb); + DCHECK_EQ(pBitmap->GetFormat(), FXDIB_Format::kArgb); const uint32_t total_results = GetValidatedOutputsCount(funcs, pCS); if (total_results == 0) return; - const CPDF_Array* pCoords = pDict->GetArrayFor("Coords"); + RetainPtr<const CPDF_Array> pCoords = pDict->GetArrayFor("Coords"); if (!pCoords) return; - float start_x = pCoords->GetNumberAt(0); - float start_y = pCoords->GetNumberAt(1); - float start_r = pCoords->GetNumberAt(2); - float end_x = pCoords->GetNumberAt(3); - float end_y = pCoords->GetNumberAt(4); - float end_r = pCoords->GetNumberAt(5); + float start_x = pCoords->GetFloatAt(0); + float start_y = pCoords->GetFloatAt(1); + float start_r = pCoords->GetFloatAt(2); + float end_x = pCoords->GetFloatAt(3); + float end_y = pCoords->GetFloatAt(4); + float end_r = pCoords->GetFloatAt(5); float t_min = 0; float t_max = 1.0f; - const CPDF_Array* pArray = pDict->GetArrayFor("Domain"); + RetainPtr<const CPDF_Array> pArray = pDict->GetArrayFor("Domain"); if (pArray) { - t_min = pArray->GetNumberAt(0); - t_max = pArray->GetNumberAt(1); + t_min = pArray->GetFloatAt(0); + t_max = pArray->GetFloatAt(1); } pArray = pDict->GetArrayFor("Extend"); const bool bStartExtend = pArray && pArray->GetBooleanAt(0, false); @@ -191,19 +198,16 @@ const float dy = end_y - start_y; const float dr = end_r - start_r; const float a = dx * dx + dy * dy - dr * dr; - const bool a_is_float_zero = IsFloatZero(a); + const bool a_is_float_zero = FXSYS_IsFloatZero(a); int width = pBitmap->GetWidth(); int height = pBitmap->GetHeight(); - int pitch = pBitmap->GetPitch(); - - bool bDecreasing = - (dr < 0 && static_cast<int>(sqrt(dx * dx + dy * dy)) < -dr); + bool bDecreasing = dr < 0 && static_cast<int>(FXSYS_sqrt2(dx, dy)) < -dr; CFX_Matrix matrix = mtObject2Bitmap.GetInverse(); for (int row = 0; row < height; row++) { uint32_t* dib_buf = - reinterpret_cast<uint32_t*>(pBitmap->GetBuffer() + row * pitch); + reinterpret_cast<uint32_t*>(pBitmap->GetWritableScanline(row).data()); for (int column = 0; column < width; column++) { CFX_PointF pos = matrix.Transform( CFX_PointF(static_cast<float>(column), static_cast<float>(row))); @@ -212,7 +216,7 @@ float b = -2 * (pos_dx * dx + pos_dy * dy + start_r * dr); float c = pos_dx * pos_dx + pos_dy * pos_dy - start_r * start_r; float s; - if (IsFloatZero(b)) { + if (FXSYS_IsFloatZero(b)) { s = sqrt(-c / a); } else if (a_is_float_zero) { s = -c / b; @@ -256,57 +260,57 @@ const std::vector<std::unique_ptr<CPDF_Function>>& funcs, const RetainPtr<CPDF_ColorSpace>& pCS, int alpha) { - ASSERT(pBitmap->GetFormat() == FXDIB_Argb); + DCHECK_EQ(pBitmap->GetFormat(), FXDIB_Format::kArgb); const uint32_t total_results = GetValidatedOutputsCount(funcs, pCS); if (total_results == 0) return; - const CPDF_Array* pDomain = pDict->GetArrayFor("Domain"); + RetainPtr<const CPDF_Array> pDomain = pDict->GetArrayFor("Domain"); float xmin = 0.0f; float ymin = 0.0f; float xmax = 1.0f; float ymax = 1.0f; if (pDomain) { - xmin = pDomain->GetNumberAt(0); - xmax = pDomain->GetNumberAt(1); - ymin = pDomain->GetNumberAt(2); - ymax = pDomain->GetNumberAt(3); + xmin = pDomain->GetFloatAt(0); + xmax = pDomain->GetFloatAt(1); + ymin = pDomain->GetFloatAt(2); + ymax = pDomain->GetFloatAt(3); } CFX_Matrix mtDomain2Target = pDict->GetMatrixFor("Matrix"); CFX_Matrix matrix = mtObject2Bitmap.GetInverse() * mtDomain2Target.GetInverse(); int width = pBitmap->GetWidth(); int height = pBitmap->GetHeight(); - int pitch = pBitmap->GetPitch(); - ASSERT(total_results >= CountOutputsFromFunctions(funcs)); - ASSERT(total_results >= pCS->CountComponents()); + DCHECK(total_results >= CountOutputsFromFunctions(funcs)); + DCHECK(total_results >= pCS->CountComponents()); std::vector<float> result_array(total_results); for (int row = 0; row < height; ++row) { - uint32_t* dib_buf = (uint32_t*)(pBitmap->GetBuffer() + row * pitch); + uint32_t* dib_buf = + reinterpret_cast<uint32_t*>(pBitmap->GetWritableScanline(row).data()); for (int column = 0; column < width; column++) { CFX_PointF pos = matrix.Transform( CFX_PointF(static_cast<float>(column), static_cast<float>(row))); if (pos.x < xmin || pos.x > xmax || pos.y < ymin || pos.y > ymax) continue; - float input[] = {pos.x, pos.y}; - int offset = 0; + float input[2] = {pos.x, pos.y}; + pdfium::span<float> result_span = pdfium::make_span(result_array); for (const auto& func : funcs) { - if (func) { - int nresults; - if (func->Call(input, 2, &result_array[offset], &nresults)) - offset += nresults; - } + if (!func) + continue; + absl::optional<uint32_t> nresults = func->Call(input, result_span); + if (nresults.has_value()) + result_span = result_span.subspan(nresults.value()); } - float R = 0.0f; float G = 0.0f; float B = 0.0f; - pCS->GetRGB(result_array.data(), &R, &G, &B); - dib_buf[column] = FXARGB_TODIB(ArgbEncode( - alpha, (int32_t)(R * 255), (int32_t)(G * 255), (int32_t)(B * 255))); + pCS->GetRGB(result_array, &R, &G, &B); + dib_buf[column] = ArgbEncode(alpha, static_cast<int32_t>(R * 255), + static_cast<int32_t>(G * 255), + static_cast<int32_t>(B * 255)); } } } @@ -340,9 +344,8 @@ if (min_y == max_y) return; - int min_yi = std::max(static_cast<int>(floor(min_y)), 0); - int max_yi = static_cast<int>(ceil(max_y)); - + int min_yi = std::max(static_cast<int>(floorf(min_y)), 0); + int max_yi = static_cast<int>(ceilf(max_y)); if (max_yi >= pBitmap->GetHeight()) max_yi = pBitmap->GetHeight() - 1; @@ -371,40 +374,42 @@ if (nIntersects != 2) continue; - int min_x, max_x, start_index, end_index; + int min_x; + int max_x; + int start_index; + int end_index; if (inter_x[0] < inter_x[1]) { - min_x = (int)floor(inter_x[0]); - max_x = (int)ceil(inter_x[1]); + min_x = static_cast<int>(floorf(inter_x[0])); + max_x = static_cast<int>(ceilf(inter_x[1])); start_index = 0; end_index = 1; } else { - min_x = (int)floor(inter_x[1]); - max_x = (int)ceil(inter_x[0]); + min_x = static_cast<int>(floorf(inter_x[1])); + max_x = static_cast<int>(ceilf(inter_x[0])); start_index = 1; end_index = 0; } - int start_x = std::max(min_x, 0); - int end_x = max_x; - if (end_x > pBitmap->GetWidth()) - end_x = pBitmap->GetWidth(); - - uint8_t* dib_buf = - pBitmap->GetBuffer() + y * pBitmap->GetPitch() + start_x * 4; + int start_x = pdfium::clamp(min_x, 0, pBitmap->GetWidth()); + int end_x = pdfium::clamp(max_x, 0, pBitmap->GetWidth()); float r_unit = (r[end_index] - r[start_index]) / (max_x - min_x); float g_unit = (g[end_index] - g[start_index]) / (max_x - min_x); float b_unit = (b[end_index] - b[start_index]) / (max_x - min_x); - float R = r[start_index] + (start_x - min_x) * r_unit; - float G = g[start_index] + (start_x - min_x) * g_unit; - float B = b[start_index] + (start_x - min_x) * b_unit; + float r_result = r[start_index] + (start_x - min_x) * r_unit; + float g_result = g[start_index] + (start_x - min_x) * g_unit; + float b_result = b[start_index] + (start_x - min_x) * b_unit; + pdfium::span<uint8_t> dib_span = + pBitmap->GetWritableScanline(y).subspan(start_x * 4); + for (int x = start_x; x < end_x; x++) { - R += r_unit; - G += g_unit; - B += b_unit; - FXARGB_SETDIB(dib_buf, - ArgbEncode(alpha, (int32_t)(R * 255), (int32_t)(G * 255), - (int32_t)(B * 255))); - dib_buf += 4; + uint8_t* dib_buf = dib_span.data(); + r_result += r_unit; + g_result += g_unit; + b_result += b_unit; + FXARGB_SETDIB(dib_buf, ArgbEncode(alpha, static_cast<int>(r_result * 255), + static_cast<int>(g_result * 255), + static_cast<int>(b_result * 255))); + dib_span = dib_span.subspan(4); } } } @@ -412,21 +417,19 @@ void DrawFreeGouraudShading( const RetainPtr<CFX_DIBitmap>& pBitmap, const CFX_Matrix& mtObject2Bitmap, - const CPDF_Stream* pShadingStream, + RetainPtr<const CPDF_Stream> pShadingStream, const std::vector<std::unique_ptr<CPDF_Function>>& funcs, - const RetainPtr<CPDF_ColorSpace>& pCS, + RetainPtr<CPDF_ColorSpace> pCS, int alpha) { - ASSERT(pBitmap->GetFormat() == FXDIB_Argb); + DCHECK_EQ(pBitmap->GetFormat(), FXDIB_Format::kArgb); CPDF_MeshStream stream(kFreeFormGouraudTriangleMeshShading, funcs, - pShadingStream, pCS); + std::move(pShadingStream), std::move(pCS)); if (!stream.Load()) return; CPDF_MeshVertex triangle[3]; - memset(triangle, 0, sizeof(triangle)); - - while (!stream.BitStream()->IsEOF()) { + while (!stream.IsEOF()) { CPDF_MeshVertex vertex; uint32_t flag; if (!stream.ReadVertex(mtObject2Bitmap, &vertex, &flag)) @@ -434,9 +437,9 @@ if (flag == 0) { triangle[0] = vertex; - for (int j = 1; j < 3; j++) { - uint32_t tflag; - if (!stream.ReadVertex(mtObject2Bitmap, &triangle[j], &tflag)) + for (int i = 1; i < 3; ++i) { + uint32_t dummy_flag; + if (!stream.ReadVertex(mtObject2Bitmap, &triangle[i], &dummy_flag)) return; } } else { @@ -453,18 +456,18 @@ void DrawLatticeGouraudShading( const RetainPtr<CFX_DIBitmap>& pBitmap, const CFX_Matrix& mtObject2Bitmap, - const CPDF_Stream* pShadingStream, + RetainPtr<const CPDF_Stream> pShadingStream, const std::vector<std::unique_ptr<CPDF_Function>>& funcs, - const RetainPtr<CPDF_ColorSpace>& pCS, + RetainPtr<CPDF_ColorSpace> pCS, int alpha) { - ASSERT(pBitmap->GetFormat() == FXDIB_Argb); + DCHECK_EQ(pBitmap->GetFormat(), FXDIB_Format::kArgb); int row_verts = pShadingStream->GetDict()->GetIntegerFor("VerticesPerRow"); if (row_verts < 2) return; CPDF_MeshStream stream(kLatticeFormGouraudTriangleMeshShading, funcs, - pShadingStream, pCS); + std::move(pShadingStream), std::move(pCS)); if (!stream.Load()) return; @@ -474,7 +477,7 @@ return; int last_index = 0; - while (1) { + while (true) { vertices[1 - last_index] = stream.ReadVertexRow(mtObject2Bitmap, row_verts); if (vertices[1 - last_index].empty()) return; @@ -492,123 +495,127 @@ } } -struct Coon_BezierCoeff { - float a, b, c, d; - void FromPoints(float p0, float p1, float p2, float p3) { +struct CoonBezierCoeff { + void InitFromPoints(float p0, float p1, float p2, float p3) { a = -p0 + 3 * p1 - 3 * p2 + p3; b = 3 * p0 - 6 * p1 + 3 * p2; c = -3 * p0 + 3 * p1; d = p0; } - Coon_BezierCoeff first_half() { - Coon_BezierCoeff result; - result.a = a / 8; - result.b = b / 4; - result.c = c / 2; - result.d = d; - return result; - } - Coon_BezierCoeff second_half() { - Coon_BezierCoeff result; - result.a = a / 8; - result.b = 3 * a / 8 + b / 4; - result.c = 3 * a / 8 + b / 2 + c / 2; - result.d = a / 8 + b / 4 + c / 2 + d; - return result; - } - void GetPoints(float p[4]) { - p[0] = d; - p[1] = c / 3 + p[0]; - p[2] = b / 3 - p[0] + 2 * p[1]; - p[3] = a + p[0] - 3 * p[1] + 3 * p[2]; - } - void GetPointsReverse(float p[4]) { - p[3] = d; - p[2] = c / 3 + p[3]; - p[1] = b / 3 - p[3] + 2 * p[2]; - p[0] = a + p[3] - 3 * p[2] + 3 * p[1]; - } - void BezierInterpol(Coon_BezierCoeff& C1, - Coon_BezierCoeff& C2, - Coon_BezierCoeff& D1, - Coon_BezierCoeff& D2) { + + void InitFromBezierInterpolation(const CoonBezierCoeff& C1, + const CoonBezierCoeff& C2, + const CoonBezierCoeff& D1, + const CoonBezierCoeff& D2) { a = (D1.a + D2.a) / 2; b = (D1.b + D2.b) / 2; c = (D1.c + D2.c) / 2 - (C1.a / 8 + C1.b / 4 + C1.c / 2) + (C2.a / 8 + C2.b / 4) + (-C1.d + D2.d) / 2 - (C2.a + C2.b) / 2; d = C1.a / 8 + C1.b / 4 + C1.c / 2 + C1.d; } - float Distance() { + + CoonBezierCoeff first_half() const { + CoonBezierCoeff result; + result.a = a / 8; + result.b = b / 4; + result.c = c / 2; + result.d = d; + return result; + } + + CoonBezierCoeff second_half() const { + CoonBezierCoeff result; + result.a = a / 8; + result.b = 3 * a / 8 + b / 4; + result.c = 3 * a / 8 + b / 2 + c / 2; + result.d = a / 8 + b / 4 + c / 2 + d; + return result; + } + + void GetPoints(float p[4]) const { + p[0] = d; + p[1] = c / 3 + p[0]; + p[2] = b / 3 - p[0] + 2 * p[1]; + p[3] = a + p[0] - 3 * p[1] + 3 * p[2]; + } + + float Distance() const { float dis = a + b + c; return dis < 0 ? -dis : dis; } + + float a; + float b; + float c; + float d; }; -struct Coon_Bezier { - Coon_BezierCoeff x, y; - void FromPoints(float x0, - float y0, - float x1, - float y1, - float x2, - float y2, - float x3, - float y3) { - x.FromPoints(x0, x1, x2, x3); - y.FromPoints(y0, y1, y2, y3); +struct CoonBezier { + void InitFromPoints(float x0, + float y0, + float x1, + float y1, + float x2, + float y2, + float x3, + float y3) { + x.InitFromPoints(x0, x1, x2, x3); + y.InitFromPoints(y0, y1, y2, y3); } - Coon_Bezier first_half() { - Coon_Bezier result; + void InitFromBezierInterpolation(const CoonBezier& C1, + const CoonBezier& C2, + const CoonBezier& D1, + const CoonBezier& D2) { + x.InitFromBezierInterpolation(C1.x, C2.x, D1.x, D2.x); + y.InitFromBezierInterpolation(C1.y, C2.y, D1.y, D2.y); + } + + CoonBezier first_half() const { + CoonBezier result; result.x = x.first_half(); result.y = y.first_half(); return result; } - Coon_Bezier second_half() { - Coon_Bezier result; + CoonBezier second_half() const { + CoonBezier result; result.x = x.second_half(); result.y = y.second_half(); return result; } - void BezierInterpol(Coon_Bezier& C1, - Coon_Bezier& C2, - Coon_Bezier& D1, - Coon_Bezier& D2) { - x.BezierInterpol(C1.x, C2.x, D1.x, D2.x); - y.BezierInterpol(C1.y, C2.y, D1.y, D2.y); + void GetPoints(pdfium::span<CFX_Path::Point> path_points) const { + constexpr size_t kPointsCount = 4; + float points_x[kPointsCount]; + float points_y[kPointsCount]; + x.GetPoints(points_x); + y.GetPoints(points_y); + for (size_t i = 0; i < kPointsCount; ++i) + path_points[i].m_Point = {points_x[i], points_y[i]}; } - void GetPoints(std::vector<FX_PATHPOINT>& pPoints, size_t start_idx) { - float p[4]; - int i; - x.GetPoints(p); - for (i = 0; i < 4; i++) - pPoints[start_idx + i].m_Point.x = p[i]; - - y.GetPoints(p); - for (i = 0; i < 4; i++) - pPoints[start_idx + i].m_Point.y = p[i]; + void GetPointsReverse(pdfium::span<CFX_Path::Point> path_points) const { + constexpr size_t kPointsCount = 4; + float points_x[kPointsCount]; + float points_y[kPointsCount]; + x.GetPoints(points_x); + y.GetPoints(points_y); + for (size_t i = 0; i < kPointsCount; ++i) { + size_t reverse_index = kPointsCount - i - 1; + path_points[i].m_Point = {points_x[reverse_index], + points_y[reverse_index]}; + } } - void GetPointsReverse(std::vector<FX_PATHPOINT>& pPoints, size_t start_idx) { - float p[4]; - int i; - x.GetPointsReverse(p); - for (i = 0; i < 4; i++) - pPoints[i + start_idx].m_Point.x = p[i]; + float Distance() const { return x.Distance() + y.Distance(); } - y.GetPointsReverse(p); - for (i = 0; i < 4; i++) - pPoints[i + start_idx].m_Point.y = p[i]; - } - - float Distance() { return x.Distance() + y.Distance(); } + CoonBezierCoeff x; + CoonBezierCoeff y; }; int Interpolate(int p1, int p2, int delta1, int delta2, bool* overflow) { - pdfium::base::CheckedNumeric<int> p = p2; + FX_SAFE_INT32 p = p2; p -= p1; p *= delta1; p /= delta2; @@ -632,15 +639,11 @@ return Interpolate(x1, x2, y, y_scale, overflow); } -struct Coon_Color { - Coon_Color() { memset(comp, 0, sizeof(int) * 3); } +struct CoonColor { + CoonColor() = default; // Returns true if successful, false if overflow detected. - bool BiInterpol(Coon_Color colors[4], - int x, - int y, - int x_scale, - int y_scale) { + bool BiInterpol(CoonColor colors[4], int x, int y, int x_scale, int y_scale) { bool overflow = false; for (int i = 0; i < 3; i++) { comp[i] = BiInterpolImpl(colors[0].comp[i], colors[1].comp[i], @@ -650,27 +653,28 @@ return !overflow; } - int Distance(Coon_Color& o) { + int Distance(const CoonColor& o) const { return std::max({abs(comp[0] - o.comp[0]), abs(comp[1] - o.comp[1]), abs(comp[2] - o.comp[2])}); } - int comp[3]; + int comp[3] = {}; }; -#define COONCOLOR_THRESHOLD 4 -struct CPDF_PatchDrawer { +struct PatchDrawer { + static constexpr int kCoonColorThreshold = 4; + void Draw(int x_scale, int y_scale, int left, int bottom, - Coon_Bezier C1, - Coon_Bezier C2, - Coon_Bezier D1, - Coon_Bezier D2) { + CoonBezier C1, + CoonBezier C2, + CoonBezier D1, + CoonBezier D2) { bool bSmall = C1.Distance() < 2 && C2.Distance() < 2 && D1.Distance() < 2 && D2.Distance() < 2; - Coon_Color div_colors[4]; + CoonColor div_colors[4]; int d_bottom = 0; int d_left = 0; int d_top = 0; @@ -699,35 +703,37 @@ } if (bSmall || - (d_bottom < COONCOLOR_THRESHOLD && d_left < COONCOLOR_THRESHOLD && - d_top < COONCOLOR_THRESHOLD && d_right < COONCOLOR_THRESHOLD)) { - std::vector<FX_PATHPOINT>& pPoints = path.GetPoints(); - C1.GetPoints(pPoints, 0); - D2.GetPoints(pPoints, 3); - C2.GetPointsReverse(pPoints, 6); - D1.GetPointsReverse(pPoints, 9); - int fillFlags = FXFILL_WINDING | FXFILL_FULLCOVER; + (d_bottom < kCoonColorThreshold && d_left < kCoonColorThreshold && + d_top < kCoonColorThreshold && d_right < kCoonColorThreshold)) { + pdfium::span<CFX_Path::Point> points = path.GetPoints(); + C1.GetPoints(points.subspan(0, 4)); + D2.GetPoints(points.subspan(3, 4)); + C2.GetPointsReverse(points.subspan(6, 4)); + D1.GetPointsReverse(points.subspan(9, 4)); + CFX_FillRenderOptions fill_options( + CFX_FillRenderOptions::WindingOptions()); + fill_options.full_cover = true; if (bNoPathSmooth) - fillFlags |= FXFILL_NOPATHSMOOTH; + fill_options.aliased_path = true; pDevice->DrawPath( - &path, nullptr, nullptr, + path, nullptr, nullptr, ArgbEncode(alpha, div_colors[0].comp[0], div_colors[0].comp[1], div_colors[0].comp[2]), - 0, fillFlags); + 0, fill_options); } else { - if (d_bottom < COONCOLOR_THRESHOLD && d_top < COONCOLOR_THRESHOLD) { - Coon_Bezier m1; - m1.BezierInterpol(D1, D2, C1, C2); + if (d_bottom < kCoonColorThreshold && d_top < kCoonColorThreshold) { + CoonBezier m1; + m1.InitFromBezierInterpolation(D1, D2, C1, C2); y_scale *= 2; bottom *= 2; Draw(x_scale, y_scale, left, bottom, C1, m1, D1.first_half(), D2.first_half()); Draw(x_scale, y_scale, left, bottom + 1, m1, C2, D1.second_half(), D2.second_half()); - } else if (d_left < COONCOLOR_THRESHOLD && - d_right < COONCOLOR_THRESHOLD) { - Coon_Bezier m2; - m2.BezierInterpol(C1, C2, D1, D2); + } else if (d_left < kCoonColorThreshold && + d_right < kCoonColorThreshold) { + CoonBezier m2; + m2.InitFromBezierInterpolation(C1, C2, D1, D2); x_scale *= 2; left *= 2; Draw(x_scale, y_scale, left, bottom, C1.first_half(), C2.first_half(), @@ -735,13 +741,14 @@ Draw(x_scale, y_scale, left + 1, bottom, C1.second_half(), C2.second_half(), m2, D2); } else { - Coon_Bezier m1, m2; - m1.BezierInterpol(D1, D2, C1, C2); - m2.BezierInterpol(C1, C2, D1, D2); - Coon_Bezier m1f = m1.first_half(); - Coon_Bezier m1s = m1.second_half(); - Coon_Bezier m2f = m2.first_half(); - Coon_Bezier m2s = m2.second_half(); + CoonBezier m1; + CoonBezier m2; + m1.InitFromBezierInterpolation(D1, D2, C1, C2); + m2.InitFromBezierInterpolation(C1, C2, D1, D2); + CoonBezier m1f = m1.first_half(); + CoonBezier m1s = m1.second_half(); + CoonBezier m2f = m2.first_half(); + CoonBezier m2s = m2.second_half(); x_scale *= 2; y_scale *= 2; left *= 2; @@ -759,49 +766,54 @@ } int max_delta; - CFX_PathData path; + CFX_Path path; CFX_RenderDevice* pDevice; int bNoPathSmooth; int alpha; - Coon_Color patch_colors[4]; + CoonColor patch_colors[4]; }; void DrawCoonPatchMeshes( ShadingType type, const RetainPtr<CFX_DIBitmap>& pBitmap, const CFX_Matrix& mtObject2Bitmap, - const CPDF_Stream* pShadingStream, + RetainPtr<const CPDF_Stream> pShadingStream, const std::vector<std::unique_ptr<CPDF_Function>>& funcs, - const RetainPtr<CPDF_ColorSpace>& pCS, + RetainPtr<CPDF_ColorSpace> pCS, bool bNoPathSmooth, int alpha) { - ASSERT(pBitmap->GetFormat() == FXDIB_Argb); - ASSERT(type == kCoonsPatchMeshShading || + DCHECK_EQ(pBitmap->GetFormat(), FXDIB_Format::kArgb); + DCHECK(type == kCoonsPatchMeshShading || type == kTensorProductPatchMeshShading); CFX_DefaultRenderDevice device; - device.Attach(pBitmap, false, nullptr, false); - CPDF_MeshStream stream(type, funcs, pShadingStream, pCS); + device.Attach(pBitmap); + + CPDF_MeshStream stream(type, funcs, std::move(pShadingStream), + std::move(pCS)); if (!stream.Load()) return; - CPDF_PatchDrawer patch; + PatchDrawer patch; patch.alpha = alpha; patch.pDevice = &device; patch.bNoPathSmooth = bNoPathSmooth; for (int i = 0; i < 13; i++) { - patch.path.AppendPoint( - CFX_PointF(), i == 0 ? FXPT_TYPE::MoveTo : FXPT_TYPE::BezierTo, false); + patch.path.AppendPoint(CFX_PointF(), i == 0 + ? CFX_Path::Point::Type::kMove + : CFX_Path::Point::Type::kBezier); } CFX_PointF coords[16]; int point_count = type == kTensorProductPatchMeshShading ? 16 : 12; - while (!stream.BitStream()->IsEOF()) { + while (!stream.IsEOF()) { if (!stream.CanReadFlag()) break; uint32_t flag = stream.ReadFlag(); - int iStartPoint = 0, iStartColor = 0, i = 0; + int iStartPoint = 0; + int iStartColor = 0; + int i = 0; if (flag) { iStartPoint = 4; iStartColor = 2; @@ -809,11 +821,12 @@ for (i = 0; i < 4; i++) { tempCoords[i] = coords[(flag * 3 + i) % 12]; } - memcpy(coords, tempCoords, sizeof(tempCoords)); - Coon_Color tempColors[2]; - tempColors[0] = patch.patch_colors[flag]; - tempColors[1] = patch.patch_colors[(flag + 1) % 4]; - memcpy(patch.patch_colors, tempColors, sizeof(Coon_Color) * 2); + fxcrt::spancpy(pdfium::make_span(coords), pdfium::make_span(tempCoords)); + CoonColor tempColors[2] = { + tempColors[0] = patch.patch_colors[flag], + tempColors[1] = patch.patch_colors[(flag + 1) % 4]}; + fxcrt::spancpy(pdfium::make_span(patch.patch_colors), + pdfium::make_span(tempColors)); } for (i = iStartPoint; i < point_count; i++) { if (!stream.CanReadCoords()) @@ -830,24 +843,28 @@ float b; std::tie(r, g, b) = stream.ReadColor(); - patch.patch_colors[i].comp[0] = (int32_t)(r * 255); - patch.patch_colors[i].comp[1] = (int32_t)(g * 255); - patch.patch_colors[i].comp[2] = (int32_t)(b * 255); + patch.patch_colors[i].comp[0] = static_cast<int32_t>(r * 255); + patch.patch_colors[i].comp[1] = static_cast<int32_t>(g * 255); + patch.patch_colors[i].comp[2] = static_cast<int32_t>(b * 255); } - CFX_FloatRect bbox = CFX_FloatRect::GetBBox(coords, point_count); + CFX_FloatRect bbox = + CFX_FloatRect::GetBBox(pdfium::make_span(coords).first(point_count)); if (bbox.right <= 0 || bbox.left >= (float)pBitmap->GetWidth() || bbox.top <= 0 || bbox.bottom >= (float)pBitmap->GetHeight()) { continue; } - Coon_Bezier C1, C2, D1, D2; - C1.FromPoints(coords[0].x, coords[0].y, coords[11].x, coords[11].y, - coords[10].x, coords[10].y, coords[9].x, coords[9].y); - C2.FromPoints(coords[3].x, coords[3].y, coords[4].x, coords[4].y, - coords[5].x, coords[5].y, coords[6].x, coords[6].y); - D1.FromPoints(coords[0].x, coords[0].y, coords[1].x, coords[1].y, - coords[2].x, coords[2].y, coords[3].x, coords[3].y); - D2.FromPoints(coords[9].x, coords[9].y, coords[8].x, coords[8].y, - coords[7].x, coords[7].y, coords[6].x, coords[6].y); + CoonBezier C1; + CoonBezier C2; + CoonBezier D1; + CoonBezier D2; + C1.InitFromPoints(coords[0].x, coords[0].y, coords[11].x, coords[11].y, + coords[10].x, coords[10].y, coords[9].x, coords[9].y); + C2.InitFromPoints(coords[3].x, coords[3].y, coords[4].x, coords[4].y, + coords[5].x, coords[5].y, coords[6].x, coords[6].y); + D1.InitFromPoints(coords[0].x, coords[0].y, coords[1].x, coords[1].y, + coords[2].x, coords[2].y, coords[3].x, coords[3].y); + D2.InitFromPoints(coords[9].x, coords[9].y, coords[8].x, coords[8].y, + coords[7].x, coords[7].y, coords[6].x, coords[6].y); patch.Draw(1, 1, 0, 0, C1, C2, D1, D2); } } @@ -863,25 +880,26 @@ const FX_RECT& clip_rect, int alpha, const CPDF_RenderOptions& options) { - const auto& funcs = pPattern->GetFuncs(); - const CPDF_Dictionary* pDict = pPattern->GetShadingObject()->GetDict(); RetainPtr<CPDF_ColorSpace> pColorSpace = pPattern->GetCS(); if (!pColorSpace) return; FX_ARGB background = 0; + RetainPtr<const CPDF_Dictionary> pDict = + pPattern->GetShadingObject()->GetDict(); if (!pPattern->IsShadingObject() && pDict->KeyExist("Background")) { - const CPDF_Array* pBackColor = pDict->GetArrayFor("Background"); + RetainPtr<const CPDF_Array> pBackColor = pDict->GetArrayFor("Background"); if (pBackColor && pBackColor->size() >= pColorSpace->CountComponents()) { - std::vector<float> comps = - ReadArrayElementsToVector(pBackColor, pColorSpace->CountComponents()); + std::vector<float> comps = ReadArrayElementsToVector( + pBackColor.Get(), pColorSpace->CountComponents()); float R = 0.0f; float G = 0.0f; float B = 0.0f; - pColorSpace->GetRGB(comps.data(), &R, &G, &B); - background = ArgbEncode(255, (int32_t)(R * 255), (int32_t)(G * 255), - (int32_t)(B * 255)); + pColorSpace->GetRGB(comps, &R, &G, &B); + background = ArgbEncode(255, static_cast<int32_t>(R * 255), + static_cast<int32_t>(G * 255), + static_cast<int32_t>(B * 255)); } } FX_RECT clip_rect_bbox = clip_rect; @@ -891,64 +909,80 @@ } bool bAlphaMode = options.ColorModeIs(CPDF_RenderOptions::kAlpha); if (pDevice->GetDeviceCaps(FXDC_RENDER_CAPS) & FXRC_SHADING && - pDevice->GetDeviceDriver()->DrawShading( - pPattern, &mtMatrix, clip_rect_bbox, alpha, bAlphaMode)) { + pDevice->DrawShading(pPattern, &mtMatrix, clip_rect_bbox, alpha, + bAlphaMode)) { return; } CPDF_DeviceBuffer buffer(pContext, pDevice, clip_rect_bbox, pCurObj, 150); if (!buffer.Initialize()) return; - CFX_Matrix FinalMatrix = mtMatrix * buffer.GetMatrix(); RetainPtr<CFX_DIBitmap> pBitmap = buffer.GetBitmap(); - if (!pBitmap->GetBuffer()) + if (pBitmap->GetBuffer().empty()) return; - pBitmap->Clear(background); + if (background != 0) { + pBitmap->Clear(background); + } + const CFX_Matrix final_matrix = mtMatrix * buffer.GetMatrix(); + const auto& funcs = pPattern->GetFuncs(); switch (pPattern->GetShadingType()) { case kInvalidShading: case kMaxShading: return; case kFunctionBasedShading: - DrawFuncShading(pBitmap, FinalMatrix, pDict, funcs, pColorSpace, alpha); + DrawFuncShading(pBitmap, final_matrix, pDict.Get(), funcs, pColorSpace, + alpha); break; case kAxialShading: - DrawAxialShading(pBitmap, FinalMatrix, pDict, funcs, pColorSpace, alpha); + DrawAxialShading(pBitmap, final_matrix, pDict.Get(), funcs, pColorSpace, + alpha); break; case kRadialShading: - DrawRadialShading(pBitmap, FinalMatrix, pDict, funcs, pColorSpace, alpha); + DrawRadialShading(pBitmap, final_matrix, pDict.Get(), funcs, pColorSpace, + alpha); break; case kFreeFormGouraudTriangleMeshShading: { // The shading object can be a stream or a dictionary. We do not handle // the case of dictionary at the moment. - if (const CPDF_Stream* pStream = ToStream(pPattern->GetShadingObject())) { - DrawFreeGouraudShading(pBitmap, FinalMatrix, pStream, funcs, + RetainPtr<const CPDF_Stream> pStream = + ToStream(pPattern->GetShadingObject()); + if (pStream) { + DrawFreeGouraudShading(pBitmap, final_matrix, std::move(pStream), funcs, pColorSpace, alpha); } - } break; + break; + } case kLatticeFormGouraudTriangleMeshShading: { // The shading object can be a stream or a dictionary. We do not handle // the case of dictionary at the moment. - if (const CPDF_Stream* pStream = ToStream(pPattern->GetShadingObject())) { - DrawLatticeGouraudShading(pBitmap, FinalMatrix, pStream, funcs, - pColorSpace, alpha); + RetainPtr<const CPDF_Stream> pStream = + ToStream(pPattern->GetShadingObject()); + if (pStream) { + DrawLatticeGouraudShading(pBitmap, final_matrix, std::move(pStream), + funcs, pColorSpace, alpha); } - } break; + break; + } case kCoonsPatchMeshShading: case kTensorProductPatchMeshShading: { // The shading object can be a stream or a dictionary. We do not handle // the case of dictionary at the moment. - if (const CPDF_Stream* pStream = ToStream(pPattern->GetShadingObject())) { - DrawCoonPatchMeshes(pPattern->GetShadingType(), pBitmap, FinalMatrix, - pStream, funcs, pColorSpace, + RetainPtr<const CPDF_Stream> pStream = + ToStream(pPattern->GetShadingObject()); + if (pStream) { + DrawCoonPatchMeshes(pPattern->GetShadingType(), pBitmap, final_matrix, + std::move(pStream), funcs, pColorSpace, options.GetOptions().bNoPathSmooth, alpha); } - } break; + break; + } } if (bAlphaMode) - pBitmap->LoadChannelFromAlpha(FXDIB_Red, pBitmap); + pBitmap->SetRedFromBitmap(pBitmap); if (options.ColorModeIs(CPDF_RenderOptions::kGray)) pBitmap->ConvertColorScale(0, 0xffffff); + buffer.OutputToDevice(); }
diff --git a/core/fpdfapi/render/cpdf_rendershading.h b/core/fpdfapi/render/cpdf_rendershading.h index 8c0d8a4..a8702c9 100644 --- a/core/fpdfapi/render/cpdf_rendershading.h +++ b/core/fpdfapi/render/cpdf_rendershading.h
@@ -1,4 +1,4 @@ -// Copyright 2019 PDFium Authors. All rights reserved. +// Copyright 2019 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file.
diff --git a/core/fpdfapi/render/cpdf_renderstatus.cpp b/core/fpdfapi/render/cpdf_renderstatus.cpp index 79d31b9..fe58de8 100644 --- a/core/fpdfapi/render/cpdf_renderstatus.cpp +++ b/core/fpdfapi/render/cpdf_renderstatus.cpp
@@ -1,4 +1,4 @@ -// Copyright 2016 PDFium Authors. All rights reserved. +// Copyright 2016 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -6,9 +6,9 @@ #include "core/fpdfapi/render/cpdf_renderstatus.h" +#include <stdint.h> + #include <algorithm> -#include <cmath> -#include <limits> #include <memory> #include <numeric> #include <set> @@ -29,6 +29,7 @@ #include "core/fpdfapi/page/cpdf_imageobject.h" #include "core/fpdfapi/page/cpdf_occontext.h" #include "core/fpdfapi/page/cpdf_page.h" +#include "core/fpdfapi/page/cpdf_pageimagecache.h" #include "core/fpdfapi/page/cpdf_pageobject.h" #include "core/fpdfapi/page/cpdf_pathobject.h" #include "core/fpdfapi/page/cpdf_shadingobject.h" @@ -40,34 +41,38 @@ #include "core/fpdfapi/parser/cpdf_document.h" #include "core/fpdfapi/parser/cpdf_stream.h" #include "core/fpdfapi/parser/fpdf_parser_utility.h" -#include "core/fpdfapi/render/cpdf_charposlist.h" +#include "core/fpdfapi/render/charposlist.h" #include "core/fpdfapi/render/cpdf_docrenderdata.h" #include "core/fpdfapi/render/cpdf_imagerenderer.h" -#include "core/fpdfapi/render/cpdf_pagerendercache.h" #include "core/fpdfapi/render/cpdf_rendercontext.h" #include "core/fpdfapi/render/cpdf_renderoptions.h" #include "core/fpdfapi/render/cpdf_rendershading.h" +#include "core/fpdfapi/render/cpdf_rendertiling.h" #include "core/fpdfapi/render/cpdf_scaledrenderbuffer.h" #include "core/fpdfapi/render/cpdf_textrenderer.h" #include "core/fpdfapi/render/cpdf_type3cache.h" #include "core/fxcrt/autorestorer.h" +#include "core/fxcrt/data_vector.h" +#include "core/fxcrt/fx_2d_size.h" #include "core/fxcrt/fx_safe_types.h" #include "core/fxcrt/fx_system.h" +#include "core/fxcrt/span_util.h" +#include "core/fxcrt/unowned_ptr.h" #include "core/fxge/cfx_defaultrenderdevice.h" +#include "core/fxge/cfx_fillrenderoptions.h" #include "core/fxge/cfx_glyphbitmap.h" -#include "core/fxge/cfx_pathdata.h" +#include "core/fxge/cfx_path.h" #include "core/fxge/dib/cfx_dibitmap.h" #include "core/fxge/fx_font.h" #include "core/fxge/renderdevicedriver_iface.h" #include "core/fxge/text_char_pos.h" #include "core/fxge/text_glyph_pos.h" -#include "third_party/base/compiler_specific.h" -#include "third_party/base/logging.h" -#include "third_party/base/numerics/safe_math.h" -#include "third_party/base/ptr_util.h" -#include "third_party/base/stl_util.h" +#include "third_party/base/check.h" +#include "third_party/base/containers/contains.h" +#include "third_party/base/notreached.h" +#include "third_party/base/span.h" -#ifdef _SKIA_SUPPORT_ +#if defined(_SKIA_SUPPORT_) #include "core/fxge/skia/fx_skia_device.h" #endif @@ -76,46 +81,55 @@ constexpr int kRenderMaxRecursionDepth = 64; int g_CurrentRecursionDepth = 0; -RetainPtr<CFX_DIBitmap> DrawPatternBitmap( - CPDF_Document* pDoc, - CPDF_PageRenderCache* pCache, - CPDF_TilingPattern* pPattern, - CPDF_Form* pPatternForm, - const CFX_Matrix& mtObject2Device, - int width, - int height, - const CPDF_RenderOptions::Options& draw_options) { - auto pBitmap = pdfium::MakeRetain<CFX_DIBitmap>(); - if (!pBitmap->Create(width, height, - pPattern->colored() ? FXDIB_Argb : FXDIB_8bppMask)) { - return nullptr; +CFX_FillRenderOptions GetFillOptionsForDrawPathWithBlend( + const CPDF_RenderOptions::Options& options, + const CPDF_PathObject* path_obj, + CFX_FillRenderOptions::FillType fill_type, + bool is_stroke, + bool is_type3_char) { + CFX_FillRenderOptions fill_options(fill_type); + if (fill_type != CFX_FillRenderOptions::FillType::kNoFill && options.bRectAA) + fill_options.rect_aa = true; + if (options.bNoPathSmooth) + fill_options.aliased_path = true; + if (path_obj->m_GeneralState.GetStrokeAdjust()) + fill_options.adjust_stroke = true; + if (is_stroke) + fill_options.stroke = true; + if (is_type3_char) + fill_options.text_mode = true; + + return fill_options; +} + +CFX_FillRenderOptions GetFillOptionsForDrawTextPath( + const CPDF_RenderOptions::Options& options, + const CPDF_TextObject* text_obj, + bool is_stroke, + bool is_fill) { + CFX_FillRenderOptions fill_options; + if (is_stroke && is_fill) { + fill_options.stroke = true; + fill_options.stroke_text_mode = true; } - CFX_DefaultRenderDevice bitmap_device; - bitmap_device.Attach(pBitmap, false, nullptr, false); - pBitmap->Clear(0); - CFX_FloatRect cell_bbox = - pPattern->pattern_to_form().TransformRect(pPattern->bbox()); - cell_bbox = mtObject2Device.TransformRect(cell_bbox); - CFX_FloatRect bitmap_rect(0.0f, 0.0f, width, height); - CFX_Matrix mtAdjust; - mtAdjust.MatchRect(bitmap_rect, cell_bbox); + if (text_obj->m_GeneralState.GetStrokeAdjust()) + fill_options.adjust_stroke = true; + if (options.bNoTextSmooth) + fill_options.aliased_path = true; - CFX_Matrix mtPattern2Bitmap = mtObject2Device * mtAdjust; - CPDF_RenderOptions options; - if (!pPattern->colored()) - options.SetColorMode(CPDF_RenderOptions::kAlpha); + return fill_options; +} - options.GetOptions() = draw_options; - options.GetOptions().bForceHalftone = true; - - CPDF_RenderContext context(pDoc, nullptr, pCache); - context.AppendLayer(pPatternForm, &mtPattern2Bitmap); - context.Render(&bitmap_device, &options, nullptr); -#if defined _SKIA_SUPPORT_PATHS_ - bitmap_device.Flush(true); - pBitmap->UnPreMultiply(); +FXDIB_Format GetFormatForLuminosity(bool is_luminosity) { + if (!is_luminosity) + return FXDIB_Format::k8bppMask; +#if BUILDFLAG(IS_APPLE) + return FXDIB_Format::kRgb32; +#else + if (CFX_DefaultRenderDevice::SkiaIsDefaultRenderer()) + return FXDIB_Format::kRgb32; + return FXDIB_Format::kRgb; #endif - return pBitmap; } bool IsAvailableMatrix(const CFX_Matrix& matrix) { @@ -146,29 +160,13 @@ return pChar && (!pChar->colored() || MissingStrokeColor(pColorState)); } -#if defined(_SKIA_SUPPORT_) || defined(_SKIA_SUPPORT_PATHS_) -class ScopedSkiaDeviceFlush { - public: - explicit ScopedSkiaDeviceFlush(CFX_RenderDevice* pDevice) - : m_pDevice(pDevice) {} - - ScopedSkiaDeviceFlush(const ScopedSkiaDeviceFlush&) = delete; - ScopedSkiaDeviceFlush& operator=(const ScopedSkiaDeviceFlush&) = delete; - - ~ScopedSkiaDeviceFlush() { m_pDevice->Flush(/*release=*/false); } - - private: - CFX_RenderDevice* const m_pDevice; -}; -#endif - } // namespace CPDF_RenderStatus::CPDF_RenderStatus(CPDF_RenderContext* pContext, CFX_RenderDevice* pDevice) : m_pContext(pContext), m_pDevice(pDevice) {} -CPDF_RenderStatus::~CPDF_RenderStatus() {} +CPDF_RenderStatus::~CPDF_RenderStatus() = default; void CPDF_RenderStatus::Initialize(const CPDF_RenderStatus* pParentStatus, const CPDF_GraphicStates* pInitialStates) { @@ -198,9 +196,6 @@ void CPDF_RenderStatus::RenderObjectList( const CPDF_PageObjectHolder* pObjectHolder, const CFX_Matrix& mtObj2Device) { -#if defined _SKIA_SUPPORT_ - DebugVerifyDeviceIsPreMultiplied(); -#endif CFX_FloatRect clip_rect = mtObj2Device.GetInverse().TransformRect( CFX_FloatRect(m_pDevice->GetClipBox())); for (const auto& pCurObj : *pObjectHolder) { @@ -221,23 +216,16 @@ if (m_bStopped) return; } -#if defined _SKIA_SUPPORT_ - DebugVerifyDeviceIsPreMultiplied(); -#endif } void CPDF_RenderStatus::RenderSingleObject(CPDF_PageObject* pObj, const CFX_Matrix& mtObj2Device) { -#if defined _SKIA_SUPPORT_ - DebugVerifyDeviceIsPreMultiplied(); -#endif AutoRestorer<int> restorer(&g_CurrentRecursionDepth); if (++g_CurrentRecursionDepth > kRenderMaxRecursionDepth) { return; } m_pCurObj = pObj; - if (m_Options.GetOCContext() && - !m_Options.GetOCContext()->CheckObjectVisible(pObj)) { + if (!m_Options.CheckPageObjectVisible(pObj)) { return; } ProcessClipPath(pObj->m_ClipPath, mtObj2Device); @@ -245,9 +233,6 @@ return; } ProcessObjectNoClip(pObj, mtObj2Device); -#if defined _SKIA_SUPPORT_ - DebugVerifyDeviceIsPreMultiplied(); -#endif } bool CPDF_RenderStatus::ContinueSingleObject(CPDF_PageObject* pObj, @@ -264,10 +249,8 @@ } m_pCurObj = pObj; - if (m_Options.GetOCContext() && - !m_Options.GetOCContext()->CheckObjectVisible(pObj)) { + if (!m_Options.CheckPageObjectVisible(pObj)) return false; - } ProcessClipPath(pObj->m_ClipPath, mtObj2Device); if (ProcessTransparency(pObj, mtObj2Device)) @@ -278,8 +261,8 @@ return false; } - m_pImageRenderer = pdfium::MakeUnique<CPDF_ImageRenderer>(); - if (!m_pImageRenderer->Start(this, pObj->AsImage(), mtObj2Device, false, + m_pImageRenderer = std::make_unique<CPDF_ImageRenderer>(this); + if (!m_pImageRenderer->Start(pObj->AsImage(), mtObj2Device, false, BlendMode::kNormal)) { if (!m_pImageRenderer->GetResult()) DrawObjWithBackground(pObj, mtObj2Device); @@ -299,42 +282,36 @@ void CPDF_RenderStatus::ProcessObjectNoClip(CPDF_PageObject* pObj, const CFX_Matrix& mtObj2Device) { -#if defined _SKIA_SUPPORT_ - DebugVerifyDeviceIsPreMultiplied(); -#endif bool bRet = false; switch (pObj->GetType()) { - case CPDF_PageObject::TEXT: + case CPDF_PageObject::Type::kText: bRet = ProcessText(pObj->AsText(), mtObj2Device, nullptr); break; - case CPDF_PageObject::PATH: + case CPDF_PageObject::Type::kPath: bRet = ProcessPath(pObj->AsPath(), mtObj2Device); break; - case CPDF_PageObject::IMAGE: + case CPDF_PageObject::Type::kImage: bRet = ProcessImage(pObj->AsImage(), mtObj2Device); break; - case CPDF_PageObject::SHADING: + case CPDF_PageObject::Type::kShading: ProcessShading(pObj->AsShading(), mtObj2Device); return; - case CPDF_PageObject::FORM: + case CPDF_PageObject::Type::kForm: bRet = ProcessForm(pObj->AsForm(), mtObj2Device); break; } if (!bRet) DrawObjWithBackground(pObj, mtObj2Device); -#if defined _SKIA_SUPPORT_ - DebugVerifyDeviceIsPreMultiplied(); -#endif } bool CPDF_RenderStatus::DrawObjWithBlend(CPDF_PageObject* pObj, const CFX_Matrix& mtObj2Device) { switch (pObj->GetType()) { - case CPDF_PageObject::PATH: + case CPDF_PageObject::Type::kPath: return ProcessPath(pObj->AsPath(), mtObj2Device); - case CPDF_PageObject::IMAGE: + case CPDF_PageObject::Type::kImage: return ProcessImage(pObj->AsImage(), mtObj2Device); - case CPDF_PageObject::FORM: + case CPDF_PageObject::Type::kForm: return ProcessForm(pObj->AsForm(), mtObj2Device); default: return false; @@ -347,26 +324,22 @@ if (rect.IsEmpty()) return; - int res = 300; - if (pObj->IsImage() && m_pDevice->GetDeviceType() == DeviceType::kPrinter) - res = 0; - + int res = (pObj->IsImage() && m_bPrint) ? 0 : 300; CPDF_ScaledRenderBuffer buffer; - if (!buffer.Initialize(m_pContext.Get(), m_pDevice, rect, pObj, &m_Options, - res)) { + if (!buffer.Initialize(m_pContext, m_pDevice, rect, pObj, &m_Options, res)) { return; } + RetainPtr<const CPDF_Dictionary> pFormResource; CFX_Matrix matrix = mtObj2Device * buffer.GetMatrix(); - const CPDF_Dictionary* pFormResource = nullptr; const CPDF_FormObject* pFormObj = pObj->AsForm(); if (pFormObj) pFormResource = pFormObj->form()->GetDict()->GetDictFor("Resources"); - CPDF_RenderStatus status(m_pContext.Get(), buffer.GetDevice()); + CPDF_RenderStatus status(m_pContext, buffer.GetDevice()); status.SetOptions(m_Options); status.SetDeviceMatrix(buffer.GetMatrix()); status.SetTransparency(m_Transparency); status.SetDropObjects(m_bDropObjects); - status.SetFormResource(pFormResource); + status.SetFormResource(std::move(pFormResource)); status.Initialize(nullptr, nullptr); status.RenderSingleObject(pObj, matrix); buffer.OutputToDevice(); @@ -374,23 +347,20 @@ bool CPDF_RenderStatus::ProcessForm(const CPDF_FormObject* pFormObj, const CFX_Matrix& mtObj2Device) { -#if defined _SKIA_SUPPORT_ - DebugVerifyDeviceIsPreMultiplied(); -#endif - const CPDF_Dictionary* pOC = pFormObj->form()->GetDict()->GetDictFor("OC"); - if (pOC && m_Options.GetOCContext() && - !m_Options.GetOCContext()->CheckOCGVisible(pOC)) { + RetainPtr<const CPDF_Dictionary> pOC = + pFormObj->form()->GetDict()->GetDictFor("OC"); + if (pOC && !m_Options.CheckOCGDictVisible(pOC.Get())) return true; - } + CFX_Matrix matrix = pFormObj->form_matrix() * mtObj2Device; - const CPDF_Dictionary* pResources = + RetainPtr<const CPDF_Dictionary> pResources = pFormObj->form()->GetDict()->GetDictFor("Resources"); - CPDF_RenderStatus status(m_pContext.Get(), m_pDevice); + CPDF_RenderStatus status(m_pContext, m_pDevice); status.SetOptions(m_Options); - status.SetStopObject(m_pStopObj.Get()); + status.SetStopObject(m_pStopObj); status.SetTransparency(m_Transparency); status.SetDropObjects(m_bDropObjects); - status.SetFormResource(pResources); + status.SetFormResource(std::move(pResources)); status.Initialize(this, pFormObj); status.m_curBlend = m_curBlend; { @@ -398,63 +368,59 @@ status.RenderObjectList(pFormObj->form(), matrix); m_bStopped = status.m_bStopped; } -#if defined _SKIA_SUPPORT_ - DebugVerifyDeviceIsPreMultiplied(); -#endif return true; } -bool CPDF_RenderStatus::ProcessPath(CPDF_PathObject* pPathObj, +bool CPDF_RenderStatus::ProcessPath(CPDF_PathObject* path_obj, const CFX_Matrix& mtObj2Device) { - int FillType = pPathObj->filltype(); - bool bStroke = pPathObj->stroke(); - ProcessPathPattern(pPathObj, mtObj2Device, &FillType, &bStroke); - if (FillType == 0 && !bStroke) + CFX_FillRenderOptions::FillType fill_type = path_obj->filltype(); + bool stroke = path_obj->stroke(); + ProcessPathPattern(path_obj, mtObj2Device, &fill_type, &stroke); + if (fill_type == CFX_FillRenderOptions::FillType::kNoFill && !stroke) return true; - uint32_t fill_argb = FillType ? GetFillArgb(pPathObj) : 0; - uint32_t stroke_argb = bStroke ? GetStrokeArgb(pPathObj) : 0; - CFX_Matrix path_matrix = pPathObj->matrix() * mtObj2Device; + // If the option to convert fill paths to stroke is enabled for forced color, + // set |fill_type| to FillType::kNoFill and |stroke| to true. + CPDF_RenderOptions::Options& options = m_Options.GetOptions(); + if (m_Options.ColorModeIs(CPDF_RenderOptions::Type::kForcedColor) && + options.bConvertFillToStroke && + fill_type != CFX_FillRenderOptions::FillType::kNoFill) { + stroke = true; + fill_type = CFX_FillRenderOptions::FillType::kNoFill; + } + + uint32_t fill_argb = fill_type != CFX_FillRenderOptions::FillType::kNoFill + ? GetFillArgb(path_obj) + : 0; + uint32_t stroke_argb = stroke ? GetStrokeArgb(path_obj) : 0; + CFX_Matrix path_matrix = path_obj->matrix() * mtObj2Device; if (!IsAvailableMatrix(path_matrix)) return true; - if (FillType && m_Options.GetOptions().bRectAA) - FillType |= FXFILL_RECT_AA; - if (m_Options.GetOptions().bFillFullcover) - FillType |= FXFILL_FULLCOVER; - if (m_Options.GetOptions().bNoPathSmooth) - FillType |= FXFILL_NOPATHSMOOTH; - if (bStroke) - FillType |= FX_FILL_STROKE; - - const CPDF_PageObject* pPageObj = - static_cast<const CPDF_PageObject*>(pPathObj); - if (pPageObj->m_GeneralState.GetStrokeAdjust()) - FillType |= FX_STROKE_ADJUST; - if (m_pType3Char) - FillType |= FX_FILL_TEXT_MODE; - - CFX_GraphState graphState = pPathObj->m_GraphState; - if (m_Options.GetOptions().bThinLine) - graphState.SetLineWidth(0); return m_pDevice->DrawPathWithBlend( - pPathObj->path().GetObject(), &path_matrix, graphState.GetObject(), - fill_argb, stroke_argb, FillType, m_curBlend); + *path_obj->path().GetObject(), &path_matrix, + path_obj->m_GraphState.GetObject(), fill_argb, stroke_argb, + GetFillOptionsForDrawPathWithBlend(options, path_obj, fill_type, stroke, + m_pType3Char), + m_curBlend); } RetainPtr<CPDF_TransferFunc> CPDF_RenderStatus::GetTransferFunc( - const CPDF_Object* pObj) const { - ASSERT(pObj); + RetainPtr<const CPDF_Object> pObj) const { + DCHECK(pObj); auto* pDocCache = CPDF_DocRenderData::FromDocument(m_pContext->GetDocument()); - return pDocCache ? pDocCache->GetTransferFunc(pObj) : nullptr; + return pDocCache ? pDocCache->GetTransferFunc(std::move(pObj)) : nullptr; } -FX_ARGB CPDF_RenderStatus::GetFillArgbInternal(CPDF_PageObject* pObj, - bool bType3) const { - const CPDF_ColorState* pColorState = &pObj->m_ColorState; - if (!bType3 && Type3CharMissingFillColor(m_pType3Char.Get(), pColorState)) +FX_ARGB CPDF_RenderStatus::GetFillArgb(CPDF_PageObject* pObj) const { + if (Type3CharMissingFillColor(m_pType3Char, &pObj->m_ColorState)) return m_T3FillColor; + return GetFillArgbForType3(pObj); +} + +FX_ARGB CPDF_RenderStatus::GetFillArgbForType3(CPDF_PageObject* pObj) const { + const CPDF_ColorState* pColorState = &pObj->m_ColorState; if (MissingFillColor(pColorState)) pColorState = &m_InitialStates.m_ColorState; @@ -464,22 +430,24 @@ int32_t alpha = static_cast<int32_t>((pObj->m_GeneralState.GetFillAlpha() * 255)); - if (pObj->m_GeneralState.GetTR()) { + RetainPtr<const CPDF_Object> pTR = pObj->m_GeneralState.GetTR(); + if (pTR) { if (!pObj->m_GeneralState.GetTransferFunc()) { - pObj->m_GeneralState.SetTransferFunc( - GetTransferFunc(pObj->m_GeneralState.GetTR())); + pObj->m_GeneralState.SetTransferFunc(GetTransferFunc(std::move(pTR))); } if (pObj->m_GeneralState.GetTransferFunc()) { colorref = pObj->m_GeneralState.GetTransferFunc()->TranslateColor(colorref); } } - return m_Options.TranslateColor(AlphaAndColorRefToArgb(alpha, colorref)); + return m_Options.TranslateObjectColor(AlphaAndColorRefToArgb(alpha, colorref), + pObj->GetType(), + CPDF_RenderOptions::RenderType::kFill); } FX_ARGB CPDF_RenderStatus::GetStrokeArgb(CPDF_PageObject* pObj) const { const CPDF_ColorState* pColorState = &pObj->m_ColorState; - if (Type3CharMissingStrokeColor(m_pType3Char.Get(), pColorState)) + if (Type3CharMissingStrokeColor(m_pType3Char, pColorState)) return m_T3FillColor; if (MissingStrokeColor(pColorState)) @@ -491,17 +459,19 @@ int32_t alpha = static_cast<int32_t>(pObj->m_GeneralState.GetStrokeAlpha() * 255); // not rounded. - if (pObj->m_GeneralState.GetTR()) { + RetainPtr<const CPDF_Object> pTR = pObj->m_GeneralState.GetTR(); + if (pTR) { if (!pObj->m_GeneralState.GetTransferFunc()) { - pObj->m_GeneralState.SetTransferFunc( - GetTransferFunc(pObj->m_GeneralState.GetTR())); + pObj->m_GeneralState.SetTransferFunc(GetTransferFunc(std::move(pTR))); } if (pObj->m_GeneralState.GetTransferFunc()) { colorref = pObj->m_GeneralState.GetTransferFunc()->TranslateColor(colorref); } } - return m_Options.TranslateColor(AlphaAndColorRefToArgb(alpha, colorref)); + return m_Options.TranslateObjectColor( + AlphaAndColorRefToArgb(alpha, colorref), pObj->GetType(), + CPDF_RenderOptions::RenderType::kStroke); } void CPDF_RenderStatus::ProcessClipPath(const CPDF_ClipPath& ClipPath, @@ -519,34 +489,36 @@ m_LastClipPath = ClipPath; m_pDevice->RestoreState(true); for (size_t i = 0; i < ClipPath.GetPathCount(); ++i) { - const CFX_PathData* pPathData = ClipPath.GetPath(i).GetObject(); - if (!pPathData) + const CFX_Path* pPath = ClipPath.GetPath(i).GetObject(); + if (!pPath) continue; - if (pPathData->GetPoints().empty()) { - CFX_PathData EmptyPath; - EmptyPath.AppendRect(-1, -1, 0, 0); - m_pDevice->SetClip_PathFill(&EmptyPath, nullptr, FXFILL_WINDING); + if (pPath->GetPoints().empty()) { + CFX_Path empty_path; + empty_path.AppendRect(-1, -1, 0, 0); + m_pDevice->SetClip_PathFill(empty_path, nullptr, + CFX_FillRenderOptions::WindingOptions()); } else { - m_pDevice->SetClip_PathFill(pPathData, &mtObj2Device, - ClipPath.GetClipType(i)); + m_pDevice->SetClip_PathFill( + *pPath, &mtObj2Device, + CFX_FillRenderOptions(ClipPath.GetClipType(i))); } } if (ClipPath.GetTextCount() == 0) return; - if (m_pDevice->GetDeviceType() == DeviceType::kDisplay && + if (!m_bPrint && !(m_pDevice->GetDeviceCaps(FXDC_RENDER_CAPS) & FXRC_SOFT_CLIP)) { return; } - std::unique_ptr<CFX_PathData> pTextClippingPath; + std::unique_ptr<CFX_Path> pTextClippingPath; for (size_t i = 0; i < ClipPath.GetTextCount(); ++i) { CPDF_TextObject* pText = ClipPath.GetText(i); if (pText) { if (!pTextClippingPath) - pTextClippingPath = pdfium::MakeUnique<CFX_PathData>(); + pTextClippingPath = std::make_unique<CFX_Path>(); ProcessText(pText, mtObj2Device, pTextClippingPath.get()); continue; } @@ -554,60 +526,55 @@ if (!pTextClippingPath) continue; - int fill_mode = FXFILL_WINDING; + CFX_FillRenderOptions fill_options(CFX_FillRenderOptions::WindingOptions()); if (m_Options.GetOptions().bNoTextSmooth) - fill_mode |= FXFILL_NOPATHSMOOTH; - m_pDevice->SetClip_PathFill(pTextClippingPath.get(), nullptr, fill_mode); + fill_options.aliased_path = true; + m_pDevice->SetClip_PathFill(*pTextClippingPath, nullptr, fill_options); pTextClippingPath.reset(); } } -bool CPDF_RenderStatus::ClipPattern(const CPDF_PageObject* pPageObj, +bool CPDF_RenderStatus::ClipPattern(const CPDF_PageObject* page_obj, const CFX_Matrix& mtObj2Device, - bool bStroke) { - if (pPageObj->IsPath()) - return SelectClipPath(pPageObj->AsPath(), mtObj2Device, bStroke); - if (pPageObj->IsImage()) { - m_pDevice->SetClip_Rect(pPageObj->GetTransformedBBox(mtObj2Device)); + bool stroke) { + if (page_obj->IsPath()) + return SelectClipPath(page_obj->AsPath(), mtObj2Device, stroke); + if (page_obj->IsImage()) { + m_pDevice->SetClip_Rect(page_obj->GetTransformedBBox(mtObj2Device)); return true; } return false; } -bool CPDF_RenderStatus::SelectClipPath(const CPDF_PathObject* pPathObj, +bool CPDF_RenderStatus::SelectClipPath(const CPDF_PathObject* path_obj, const CFX_Matrix& mtObj2Device, - bool bStroke) { - CFX_Matrix path_matrix = pPathObj->matrix() * mtObj2Device; - if (bStroke) { - CFX_GraphState graphState = pPathObj->m_GraphState; - if (m_Options.GetOptions().bThinLine) - graphState.SetLineWidth(0); - return m_pDevice->SetClip_PathStroke(pPathObj->path().GetObject(), - &path_matrix, graphState.GetObject()); + bool stroke) { + CFX_Matrix path_matrix = path_obj->matrix() * mtObj2Device; + if (stroke) { + return m_pDevice->SetClip_PathStroke(*path_obj->path().GetObject(), + &path_matrix, + path_obj->m_GraphState.GetObject()); } - int fill_mode = pPathObj->filltype(); + CFX_FillRenderOptions fill_options(path_obj->filltype()); if (m_Options.GetOptions().bNoPathSmooth) { - fill_mode |= FXFILL_NOPATHSMOOTH; + fill_options.aliased_path = true; } - return m_pDevice->SetClip_PathFill(pPathObj->path().GetObject(), &path_matrix, - fill_mode); + return m_pDevice->SetClip_PathFill(*path_obj->path().GetObject(), + &path_matrix, fill_options); } bool CPDF_RenderStatus::ProcessTransparency(CPDF_PageObject* pPageObj, const CFX_Matrix& mtObj2Device) { -#if defined _SKIA_SUPPORT_ - DebugVerifyDeviceIsPreMultiplied(); -#endif - BlendMode blend_type = pPageObj->m_GeneralState.GetBlendType(); - CPDF_Dictionary* pSMaskDict = - ToDictionary(pPageObj->m_GeneralState.GetSoftMask()); + const BlendMode blend_type = pPageObj->m_GeneralState.GetBlendType(); + RetainPtr<CPDF_Dictionary> pSMaskDict = + pPageObj->m_GeneralState.GetMutableSoftMask(); if (pSMaskDict) { if (pPageObj->IsImage() && pPageObj->AsImage()->GetImage()->GetDict()->KeyExist("SMask")) { pSMaskDict = nullptr; } } - const CPDF_Dictionary* pFormResource = nullptr; + RetainPtr<const CPDF_Dictionary> pFormResource; float group_alpha = 1.0f; CPDF_Transparency transparency = m_Transparency; bool bGroupTransparent = false; @@ -620,36 +587,8 @@ } bool bTextClip = (pPageObj->m_ClipPath.HasRef() && - pPageObj->m_ClipPath.GetTextCount() > 0 && - m_pDevice->GetDeviceType() == DeviceType::kDisplay && + pPageObj->m_ClipPath.GetTextCount() > 0 && !m_bPrint && !(m_pDevice->GetDeviceCaps(FXDC_RENDER_CAPS) & FXRC_SOFT_CLIP)); - if (m_Options.GetOptions().bOverprint && pPageObj->IsImage() && - pPageObj->m_GeneralState.GetFillOP() && - pPageObj->m_GeneralState.GetStrokeOP()) { - CPDF_Document* pDocument = nullptr; - CPDF_Page* pPage = nullptr; - if (m_pContext->GetPageCache()) { - pPage = m_pContext->GetPageCache()->GetPage(); - pDocument = pPage->GetDocument(); - } else { - pDocument = pPageObj->AsImage()->GetImage()->GetDocument(); - } - const CPDF_Dictionary* pPageResources = - pPage ? pPage->m_pPageResources.Get() : nullptr; - auto* pImageStream = pPageObj->AsImage()->GetImage()->GetStream(); - const CPDF_Object* pCSObj = - pImageStream->GetDict()->GetDirectObjectFor("ColorSpace"); - RetainPtr<CPDF_ColorSpace> pColorSpace = - CPDF_DocPageData::FromDocument(pDocument)->GetColorSpace( - pCSObj, pPageResources); - if (pColorSpace) { - int format = pColorSpace->GetFamily(); - if (format == PDFCS_DEVICECMYK || format == PDFCS_SEPARATION || - format == PDFCS_DEVICEN) { - blend_type = BlendMode::kDarken; - } - } - } if (!pSMaskDict && group_alpha == 1.0f && blend_type == BlendMode::kNormal && !bTextClip && !bGroupTransparent) { return false; @@ -685,24 +624,20 @@ return true; m_pDevice->GetDIBits(backdrop, rect.left, rect.top); } - if (!bitmap_device.Create(width, height, FXDIB_Argb, backdrop)) + if (!bitmap_device.Create(width, height, FXDIB_Format::kArgb, backdrop)) return true; - RetainPtr<CFX_DIBitmap> bitmap = bitmap_device.GetBitmap(); - bitmap->Clear(0); - CFX_Matrix new_matrix = mtObj2Device; new_matrix.Translate(-rect.left, -rect.top); RetainPtr<CFX_DIBitmap> pTextMask; if (bTextClip) { pTextMask = pdfium::MakeRetain<CFX_DIBitmap>(); - if (!pTextMask->Create(width, height, FXDIB_8bppMask)) + if (!pTextMask->Create(width, height, FXDIB_Format::k8bppMask)) return true; - pTextMask->Clear(0); CFX_DefaultRenderDevice text_device; - text_device.Attach(pTextMask, false, nullptr, false); + text_device.Attach(pTextMask); for (size_t i = 0; i < pPageObj->m_ClipPath.GetTextCount(); ++i) { CPDF_TextObject* textobj = pPageObj->m_ClipPath.GetText(i); if (!textobj) @@ -714,125 +649,116 @@ textobj->m_TextState.GetFont().Get(), textobj->m_TextState.GetFontSize(), textobj->GetTextMatrix(), &new_matrix, textobj->m_GraphState.GetObject(), 0xffffffff, 0, - nullptr, 0); + nullptr, CFX_FillRenderOptions()); } } - CPDF_RenderStatus bitmap_render(m_pContext.Get(), &bitmap_device); + CPDF_RenderStatus bitmap_render(m_pContext, &bitmap_device); bitmap_render.SetOptions(m_Options); - bitmap_render.SetStopObject(m_pStopObj.Get()); + bitmap_render.SetStopObject(m_pStopObj); bitmap_render.SetStdCS(true); bitmap_render.SetDropObjects(m_bDropObjects); - bitmap_render.SetFormResource(pFormResource); + bitmap_render.SetFormResource(std::move(pFormResource)); bitmap_render.Initialize(nullptr, nullptr); bitmap_render.ProcessObjectNoClip(pPageObj, new_matrix); -#if defined _SKIA_SUPPORT_PATHS_ - bitmap_device.Flush(true); - bitmap->UnPreMultiply(); -#endif +#if defined(_SKIA_SUPPORT_) + if (CFX_DefaultRenderDevice::SkiaIsDefaultRenderer()) { + // Safe because `CFX_SkiaDeviceDriver` always uses pre-multiplied alpha. + // TODO(crbug.com/pdfium/2011): Remove the need for this. + bitmap_device.GetBitmap()->ForcePreMultiply(); + } +#endif // _SKIA_SUPPORT m_bStopped = bitmap_render.m_bStopped; if (pSMaskDict) { CFX_Matrix smask_matrix = *pPageObj->m_GeneralState.GetSMaskMatrix() * mtObj2Device; RetainPtr<CFX_DIBBase> pSMaskSource = - LoadSMask(pSMaskDict, &rect, &smask_matrix); + LoadSMask(pSMaskDict.Get(), &rect, smask_matrix); if (pSMaskSource) - bitmap->MultiplyAlpha(pSMaskSource); + bitmap_device.MultiplyAlpha(pSMaskSource); } if (pTextMask) { - bitmap->MultiplyAlpha(pTextMask); + bitmap_device.MultiplyAlpha(pTextMask); pTextMask.Reset(); } - int32_t blitAlpha = 255; if (group_alpha != 1.0f && transparency.IsGroup()) { - blitAlpha = (int32_t)(group_alpha * 255); -#ifndef _SKIA_SUPPORT_ - bitmap->MultiplyAlpha(blitAlpha); - blitAlpha = 255; -#endif + bitmap_device.MultiplyAlpha(group_alpha); } transparency = m_Transparency; if (pPageObj->IsForm()) { transparency.SetGroup(); } - CompositeDIBitmap(bitmap, rect.left, rect.top, 0, blitAlpha, blend_type, - transparency); -#if defined _SKIA_SUPPORT_ - DebugVerifyDeviceIsPreMultiplied(); -#endif + CompositeDIBitmap(bitmap_device.GetBitmap(), rect.left, rect.top, 0, 255, + blend_type, transparency); return true; } +FX_RECT CPDF_RenderStatus::GetClippedBBox(const FX_RECT& rect) const { + FX_RECT bbox = rect; + bbox.Intersect(m_pDevice->GetClipBox()); + return bbox; +} + RetainPtr<CFX_DIBitmap> CPDF_RenderStatus::GetBackdrop( const CPDF_PageObject* pObj, - const FX_RECT& rect, - bool bBackAlphaRequired, - int* left, - int* top) { - FX_RECT bbox = rect; - bbox.Intersect(m_pDevice->GetClipBox()); - *left = bbox.left; - *top = bbox.top; + const FX_RECT& bbox, + bool bBackAlphaRequired) { int width = bbox.Width(); int height = bbox.Height(); auto pBackdrop = pdfium::MakeRetain<CFX_DIBitmap>(); if (bBackAlphaRequired && !m_bDropObjects) - pBackdrop->Create(width, height, FXDIB_Argb); + pBackdrop->Create(width, height, FXDIB_Format::kArgb); else m_pDevice->CreateCompatibleBitmap(pBackdrop, width, height); - if (!pBackdrop->GetBuffer()) + if (pBackdrop->GetBuffer().empty()) return nullptr; bool bNeedDraw; - if (pBackdrop->HasAlpha()) + if (pBackdrop->IsAlphaFormat()) bNeedDraw = !(m_pDevice->GetRenderCaps() & FXRC_ALPHA_OUTPUT); else bNeedDraw = !(m_pDevice->GetRenderCaps() & FXRC_GET_BITS); if (!bNeedDraw) { - m_pDevice->GetDIBits(pBackdrop, *left, *top); + m_pDevice->GetDIBits(pBackdrop, bbox.left, bbox.top); return pBackdrop; } CFX_Matrix FinalMatrix = m_DeviceMatrix; - FinalMatrix.Translate(-*left, -*top); - pBackdrop->Clear(pBackdrop->HasAlpha() ? 0 : 0xffffffff); + FinalMatrix.Translate(-bbox.left, -bbox.top); + if (!pBackdrop->IsAlphaFormat()) { + pBackdrop->Clear(0xffffffff); + } CFX_DefaultRenderDevice device; - device.Attach(pBackdrop, false, nullptr, false); + device.Attach(pBackdrop); m_pContext->Render(&device, pObj, &m_Options, &FinalMatrix); return pBackdrop; } std::unique_ptr<CPDF_GraphicStates> CPDF_RenderStatus::CloneObjStates( const CPDF_GraphicStates* pSrcStates, - bool bStroke) { + bool stroke) { if (!pSrcStates) return nullptr; - auto pStates = pdfium::MakeUnique<CPDF_GraphicStates>(); + auto pStates = std::make_unique<CPDF_GraphicStates>(); pStates->CopyStates(*pSrcStates); - const CPDF_Color* pObjColor = bStroke + const CPDF_Color* pObjColor = stroke ? pSrcStates->m_ColorState.GetStrokeColor() : pSrcStates->m_ColorState.GetFillColor(); if (!pObjColor->IsNull()) { pStates->m_ColorState.SetFillColorRef( - bStroke ? pSrcStates->m_ColorState.GetStrokeColorRef() - : pSrcStates->m_ColorState.GetFillColorRef()); + stroke ? pSrcStates->m_ColorState.GetStrokeColorRef() + : pSrcStates->m_ColorState.GetFillColorRef()); pStates->m_ColorState.SetStrokeColorRef( pStates->m_ColorState.GetFillColorRef()); } return pStates; } -#if defined _SKIA_SUPPORT_ -void CPDF_RenderStatus::DebugVerifyDeviceIsPreMultiplied() const { - m_pDevice->DebugVerifyBitmapIsPreMultiplied(); -} -#endif - bool CPDF_RenderStatus::ProcessText(CPDF_TextObject* textobj, const CFX_Matrix& mtObj2Device, - CFX_PathData* pClippingPath) { + CFX_Path* clipping_path) { if (textobj->GetCharCodes().empty()) return true; @@ -844,29 +770,29 @@ if (pFont->IsType3Font()) return ProcessType3Text(textobj, mtObj2Device); - bool bFill = false; - bool bStroke = false; - bool bClip = false; - if (pClippingPath) { - bClip = true; + bool is_fill = false; + bool is_stroke = false; + bool is_clip = false; + if (clipping_path) { + is_clip = true; } else { switch (text_render_mode) { case TextRenderingMode::MODE_FILL: case TextRenderingMode::MODE_FILL_CLIP: - bFill = true; + is_fill = true; break; case TextRenderingMode::MODE_STROKE: case TextRenderingMode::MODE_STROKE_CLIP: if (pFont->HasFace()) - bStroke = true; + is_stroke = true; else - bFill = true; + is_fill = true; break; case TextRenderingMode::MODE_FILL_STROKE: case TextRenderingMode::MODE_FILL_STROKE_CLIP: - bFill = true; + is_fill = true; if (pFont->HasFace()) - bStroke = true; + is_stroke = true; break; case TextRenderingMode::MODE_INVISIBLE: // Already handled above, but the compiler is not smart enough to @@ -883,14 +809,14 @@ FX_ARGB stroke_argb = 0; FX_ARGB fill_argb = 0; bool bPattern = false; - if (bStroke) { + if (is_stroke) { if (textobj->m_ColorState.GetStrokeColor()->IsPattern()) { bPattern = true; } else { stroke_argb = GetStrokeArgb(textobj); } } - if (bFill) { + if (is_fill) { if (textobj->m_ColorState.GetFillColor()->IsPattern()) { bPattern = true; } else { @@ -904,14 +830,14 @@ float font_size = textobj->m_TextState.GetFontSize(); if (bPattern) { DrawTextPathWithPattern(textobj, mtObj2Device, pFont.Get(), font_size, - &text_matrix, bFill, bStroke); + text_matrix, is_fill, is_stroke); return true; } - if (bClip || bStroke) { + if (is_clip || is_stroke) { const CFX_Matrix* pDeviceMatrix = &mtObj2Device; CFX_Matrix device_matrix; - if (bStroke) { - const float* pCTM = textobj->m_TextState.GetCTM(); + if (is_stroke) { + pdfium::span<const float> pCTM = textobj->m_TextState.GetCTM(); if (pCTM[0] != 1.0f || pCTM[3] != 1.0f) { CFX_Matrix ctm(pCTM[0], pCTM[1], pCTM[2], pCTM[3], 0, 0); text_matrix *= ctm.GetInverse(); @@ -919,20 +845,13 @@ pDeviceMatrix = &device_matrix; } } - int flag = 0; - if (bStroke && bFill) { - flag |= FX_FILL_STROKE; - flag |= FX_STROKE_TEXT_MODE; - } - if (textobj->m_GeneralState.GetStrokeAdjust()) - flag |= FX_STROKE_ADJUST; - if (m_Options.GetOptions().bNoTextSmooth) - flag |= FXFILL_NOPATHSMOOTH; return CPDF_TextRenderer::DrawTextPath( m_pDevice, textobj->GetCharCodes(), textobj->GetCharPositions(), pFont.Get(), font_size, text_matrix, pDeviceMatrix, textobj->m_GraphState.GetObject(), fill_argb, stroke_argb, - pClippingPath, flag); + clipping_path, + GetFillOptionsForDrawTextPath(m_Options.GetOptions(), textobj, + is_stroke, is_fill)); } text_matrix.Concat(mtObj2Device); return CPDF_TextRenderer::DrawNormalText( @@ -944,13 +863,12 @@ bool CPDF_RenderStatus::ProcessType3Text(CPDF_TextObject* textobj, const CFX_Matrix& mtObj2Device) { CPDF_Type3Font* pType3Font = textobj->m_TextState.GetFont()->AsType3Font(); - if (pdfium::ContainsValue(m_Type3FontCache, pType3Font)) + if (pdfium::Contains(m_Type3FontCache, pType3Font)) return true; - DeviceType device_type = m_pDevice->GetDeviceType(); FX_ARGB fill_argb = GetFillArgbForType3(textobj); int fill_alpha = FXARGB_A(fill_argb); - if (device_type != DeviceType::kDisplay && fill_alpha < 255) + if (m_bPrint && fill_alpha < 255) return false; CFX_Matrix text_matrix = textobj->GetTextMatrix(); @@ -961,7 +879,7 @@ // Must come before |glyphs|, because |glyphs| points into |refTypeCache|. std::set<RetainPtr<CPDF_Type3Cache>> refTypeCache; std::vector<TextGlyphPos> glyphs; - if (device_type == DeviceType::kDisplay) + if (!m_bPrint) glyphs.resize(textobj->GetCharCodes().size()); for (size_t iChar = 0; iChar < textobj->GetCharCodes().size(); ++iChar) { @@ -984,7 +902,7 @@ if (!glyph.m_pGlyph) continue; - Optional<CFX_Point> point = glyph.GetOrigin({0, 0}); + absl::optional<CFX_Point> point = glyph.GetOrigin({0, 0}); if (!point.has_value()) continue; @@ -1001,20 +919,20 @@ options.GetOptions().bRectAA = true; const auto* pForm = static_cast<const CPDF_Form*>(pType3Char->form()); - const CPDF_Dictionary* pFormResource = + RetainPtr<const CPDF_Dictionary> pFormResource = pForm->GetDict()->GetDictFor("Resources"); if (fill_alpha == 255) { - CPDF_RenderStatus status(m_pContext.Get(), m_pDevice); + CPDF_RenderStatus status(m_pContext, m_pDevice); status.SetOptions(options); status.SetTransparency(pForm->GetTransparency()); status.SetType3Char(pType3Char); status.SetFillColor(fill_argb); status.SetDropObjects(m_bDropObjects); - status.SetFormResource(pFormResource); + status.SetFormResource(std::move(pFormResource)); status.Initialize(this, pStates.get()); status.m_Type3FontCache = m_Type3FontCache; - status.m_Type3FontCache.push_back(pType3Font); + status.m_Type3FontCache.emplace_back(pType3Font); CFX_RenderDevice::StateRestorer restorer(m_pDevice); status.RenderObjectList(pForm, matrix); @@ -1025,32 +943,40 @@ continue; CFX_DefaultRenderDevice bitmap_device; - if (!bitmap_device.Create(rect.Width(), rect.Height(), FXDIB_Argb, - nullptr)) { + if (!bitmap_device.Create(rect.Width(), rect.Height(), + FXDIB_Format::kArgb, nullptr)) { return true; } - bitmap_device.GetBitmap()->Clear(0); - CPDF_RenderStatus status(m_pContext.Get(), &bitmap_device); + CPDF_RenderStatus status(m_pContext, &bitmap_device); status.SetOptions(options); status.SetTransparency(pForm->GetTransparency()); status.SetType3Char(pType3Char); status.SetFillColor(fill_argb); status.SetDropObjects(m_bDropObjects); - status.SetFormResource(pFormResource); + status.SetFormResource(std::move(pFormResource)); status.Initialize(this, pStates.get()); status.m_Type3FontCache = m_Type3FontCache; - status.m_Type3FontCache.push_back(pType3Font); + status.m_Type3FontCache.emplace_back(pType3Font); matrix.Translate(-rect.left, -rect.top); status.RenderObjectList(pForm, matrix); m_pDevice->SetDIBits(bitmap_device.GetBitmap(), rect.left, rect.top); } } else if (pType3Char->GetBitmap()) { - if (device_type == DeviceType::kDisplay) { + if (m_bPrint) { + CFX_Matrix image_matrix = pType3Char->matrix() * matrix; + CPDF_ImageRenderer renderer(this); + if (renderer.Start(pType3Char->GetBitmap(), fill_argb, image_matrix, + FXDIB_ResampleOptions(), false)) { + renderer.Continue(nullptr); + } + if (!renderer.GetResult()) + return false; + } else { CPDF_Document* pDoc = pType3Font->GetDocument(); RetainPtr<CPDF_Type3Cache> pCache = CPDF_DocRenderData::FromDocument(pDoc)->GetCachedType3(pType3Font); - const CFX_GlyphBitmap* pBitmap = pCache->LoadGlyph(charcode, &matrix); + const CFX_GlyphBitmap* pBitmap = pCache->LoadGlyph(charcode, matrix); if (!pBitmap) continue; @@ -1074,16 +1000,6 @@ glyphs[iChar].m_pGlyph = pBitmap; glyphs[iChar].m_Origin = origin; } - } else { - CFX_Matrix image_matrix = pType3Char->matrix() * matrix; - CPDF_ImageRenderer renderer; - if (renderer.Start(this, pType3Char->GetBitmap(), fill_argb, 255, - image_matrix, FXDIB_ResampleOptions(), false, - BlendMode::kNormal)) { - renderer.Continue(nullptr); - } - if (!renderer.GetResult()) - return false; } } } @@ -1093,15 +1009,14 @@ FX_RECT rect = GetGlyphsBBox(glyphs, 0); auto pBitmap = pdfium::MakeRetain<CFX_DIBitmap>(); - if (!pBitmap->Create(rect.Width(), rect.Height(), FXDIB_8bppMask)) + if (!pBitmap->Create(rect.Width(), rect.Height(), FXDIB_Format::k8bppMask)) return true; - pBitmap->Clear(0); for (const TextGlyphPos& glyph : glyphs) { - if (!glyph.m_pGlyph) + if (!glyph.m_pGlyph || !glyph.m_pGlyph->GetBitmap()->IsMaskFormat()) continue; - Optional<CFX_Point> point = glyph.GetOrigin({rect.left, rect.top}); + absl::optional<CFX_Point> point = glyph.GetOrigin({rect.left, rect.top}); if (!point.has_value()) continue; @@ -1118,15 +1033,15 @@ const CFX_Matrix& mtObj2Device, CPDF_Font* pFont, float font_size, - const CFX_Matrix* pTextMatrix, - bool bFill, - bool bStroke) { - if (!bStroke) { + const CFX_Matrix& mtTextMatrix, + bool fill, + bool stroke) { + if (!stroke) { std::vector<std::unique_ptr<CPDF_TextObject>> pCopy; - pCopy.push_back(std::unique_ptr<CPDF_TextObject>(textobj->Clone())); + pCopy.push_back(textobj->Clone()); CPDF_PathObject path; - path.set_filltype(FXFILL_WINDING); + path.set_filltype(CFX_FillRenderOptions::FillType::kWinding); path.m_ClipPath.CopyClipPath(m_LastClipPath); path.m_ClipPath.AppendTexts(&pCopy); path.m_ColorState = textobj->m_ColorState; @@ -1138,13 +1053,14 @@ RenderSingleObject(&path, mtObj2Device); return; } - const CPDF_CharPosList CharPosList( + + std::vector<TextCharPos> char_pos_list = GetCharPosList( textobj->GetCharCodes(), textobj->GetCharPositions(), pFont, font_size); - for (const TextCharPos& charpos : CharPosList.Get()) { + for (const TextCharPos& charpos : char_pos_list) { auto* font = charpos.m_FallbackFontPosition == -1 ? pFont->GetFont() : pFont->GetFontFallback(charpos.m_FallbackFontPosition); - const CFX_PathData* pPath = + const CFX_Path* pPath = font->LoadGlyphPath(charpos.m_GlyphIndex, charpos.m_FontCharWidth); if (!pPath) continue; @@ -1153,19 +1069,14 @@ path.m_GraphState = textobj->m_GraphState; path.m_ColorState = textobj->m_ColorState; - CFX_Matrix matrix; - if (charpos.m_bGlyphAdjust) { - matrix = CFX_Matrix(charpos.m_AdjustMatrix[0], charpos.m_AdjustMatrix[1], - charpos.m_AdjustMatrix[2], charpos.m_AdjustMatrix[3], - 0, 0); - } - matrix.Concat(CFX_Matrix(font_size, 0, 0, font_size, charpos.m_Origin.x, - charpos.m_Origin.y)); - path.set_stroke(bStroke); - path.set_filltype(bFill ? FXFILL_WINDING : 0); - path.path().Append(pPath, &matrix); - path.set_matrix(*pTextMatrix); - path.CalcBoundingBox(); + CFX_Matrix matrix = charpos.GetEffectiveMatrix(CFX_Matrix( + font_size, 0, 0, font_size, charpos.m_Origin.x, charpos.m_Origin.y)); + matrix.Concat(mtTextMatrix); + path.set_stroke(stroke); + path.set_filltype(fill ? CFX_FillRenderOptions::FillType::kWinding + : CFX_FillRenderOptions::FillType::kNoFill); + path.path().Append(*pPath, &matrix); + path.SetPathMatrix(CFX_Matrix()); ProcessPath(&path, mtObj2Device); } } @@ -1173,12 +1084,12 @@ void CPDF_RenderStatus::DrawShadingPattern(CPDF_ShadingPattern* pattern, const CPDF_PageObject* pPageObj, const CFX_Matrix& mtObj2Device, - bool bStroke) { + bool stroke) { if (!pattern->Load()) return; CFX_RenderDevice::StateRestorer restorer(m_pDevice); - if (!ClipPattern(pPageObj, mtObj2Device, bStroke)) + if (!ClipPattern(pPageObj, mtObj2Device, stroke)) return; FX_RECT rect = GetObjectClippedRect(pPageObj, mtObj2Device); @@ -1187,263 +1098,93 @@ CFX_Matrix matrix = pattern->pattern_to_form() * mtObj2Device; int alpha = - FXSYS_roundf(255 * (bStroke ? pPageObj->m_GeneralState.GetStrokeAlpha() - : pPageObj->m_GeneralState.GetFillAlpha())); - CPDF_RenderShading::Draw(m_pDevice, m_pContext.Get(), m_pCurObj.Get(), - pattern, matrix, rect, alpha, m_Options); + FXSYS_roundf(255 * (stroke ? pPageObj->m_GeneralState.GetStrokeAlpha() + : pPageObj->m_GeneralState.GetFillAlpha())); + CPDF_RenderShading::Draw(m_pDevice, m_pContext, m_pCurObj, pattern, matrix, + rect, alpha, m_Options); } void CPDF_RenderStatus::ProcessShading(const CPDF_ShadingObject* pShadingObj, const CFX_Matrix& mtObj2Device) { - FX_RECT rect = pShadingObj->GetTransformedBBox(mtObj2Device); - FX_RECT clip_box = m_pDevice->GetClipBox(); - rect.Intersect(clip_box); + FX_RECT rect = GetObjectClippedRect(pShadingObj, mtObj2Device); if (rect.IsEmpty()) return; CFX_Matrix matrix = pShadingObj->matrix() * mtObj2Device; CPDF_RenderShading::Draw( - m_pDevice, m_pContext.Get(), m_pCurObj.Get(), pShadingObj->pattern(), - matrix, rect, + m_pDevice, m_pContext, m_pCurObj, pShadingObj->pattern(), matrix, rect, FXSYS_roundf(255 * pShadingObj->m_GeneralState.GetFillAlpha()), m_Options); } -void CPDF_RenderStatus::DrawTilingPattern(CPDF_TilingPattern* pPattern, +void CPDF_RenderStatus::DrawTilingPattern(CPDF_TilingPattern* pattern, CPDF_PageObject* pPageObj, const CFX_Matrix& mtObj2Device, - bool bStroke) { - const std::unique_ptr<CPDF_Form> pPatternForm = pPattern->Load(pPageObj); + bool stroke) { + const std::unique_ptr<CPDF_Form> pPatternForm = pattern->Load(pPageObj); if (!pPatternForm) return; CFX_RenderDevice::StateRestorer restorer(m_pDevice); -#if defined(_SKIA_SUPPORT_) || defined(_SKIA_SUPPORT_PATHS_) - ScopedSkiaDeviceFlush scoped_skia_device_flush(m_pDevice); -#endif - if (!ClipPattern(pPageObj, mtObj2Device, bStroke)) + if (!ClipPattern(pPageObj, mtObj2Device, stroke)) return; FX_RECT clip_box = m_pDevice->GetClipBox(); if (clip_box.IsEmpty()) return; - const CFX_Matrix mtPattern2Device = - pPattern->pattern_to_form() * mtObj2Device; - - CFX_FloatRect cell_bbox = mtPattern2Device.TransformRect(pPattern->bbox()); - - float ceil_height = std::ceil(cell_bbox.Height()); - float ceil_width = std::ceil(cell_bbox.Width()); - - // Validate the float will fit into the int when the conversion is done. - if (!pdfium::base::IsValueInRangeForNumericType<int>(ceil_height) || - !pdfium::base::IsValueInRangeForNumericType<int>(ceil_width)) { - return; - } - - int width = static_cast<int>(ceil_width); - int height = static_cast<int>(ceil_height); - if (width <= 0) - width = 1; - if (height <= 0) - height = 1; - - CFX_FloatRect clip_box_p = - mtPattern2Device.GetInverse().TransformRect(CFX_FloatRect(clip_box)); - int min_col = static_cast<int>( - ceil((clip_box_p.left - pPattern->bbox().right) / pPattern->x_step())); - int max_col = static_cast<int>( - floor((clip_box_p.right - pPattern->bbox().left) / pPattern->x_step())); - int min_row = static_cast<int>( - ceil((clip_box_p.bottom - pPattern->bbox().top) / pPattern->y_step())); - int max_row = static_cast<int>( - floor((clip_box_p.top - pPattern->bbox().bottom) / pPattern->y_step())); - - // Make sure we can fit the needed width * height into an int. - if (height > std::numeric_limits<int>::max() / width) + RetainPtr<CFX_DIBitmap> pScreen = + CPDF_RenderTiling::Draw(this, pPageObj, pattern, pPatternForm.get(), + mtObj2Device, clip_box, stroke); + if (!pScreen) return; - if (width > clip_box.Width() || height > clip_box.Height() || - width * height > clip_box.Width() * clip_box.Height()) { - std::unique_ptr<CPDF_GraphicStates> pStates; - if (!pPattern->colored()) - pStates = CloneObjStates(pPageObj, bStroke); - - const CPDF_Dictionary* pFormDict = pPatternForm->GetDict(); - const CPDF_Dictionary* pFormResource = - pFormDict ? pFormDict->GetDictFor("Resources") : nullptr; - for (int col = min_col; col <= max_col; col++) { - for (int row = min_row; row <= max_row; row++) { - CFX_PointF original = mtPattern2Device.Transform( - CFX_PointF(col * pPattern->x_step(), row * pPattern->y_step())); - CFX_Matrix matrix = mtObj2Device; - matrix.Translate(original.x - mtPattern2Device.e, - original.y - mtPattern2Device.f); - CFX_RenderDevice::StateRestorer restorer2(m_pDevice); - CPDF_RenderStatus status(m_pContext.Get(), m_pDevice); - status.SetOptions(m_Options); - status.SetTransparency(pPatternForm->GetTransparency()); - status.SetFormResource(pFormResource); - status.SetDropObjects(m_bDropObjects); - status.Initialize(this, pStates.get()); - status.RenderObjectList(pPatternForm.get(), matrix); - } - } - return; - } - - bool bAligned = - pPattern->bbox().left == 0 && pPattern->bbox().bottom == 0 && - pPattern->bbox().right == pPattern->x_step() && - pPattern->bbox().top == pPattern->y_step() && - (mtPattern2Device.IsScaled() || mtPattern2Device.Is90Rotated()); - if (bAligned) { - int orig_x = FXSYS_roundf(mtPattern2Device.e); - int orig_y = FXSYS_roundf(mtPattern2Device.f); - min_col = (clip_box.left - orig_x) / width; - if (clip_box.left < orig_x) - min_col--; - - max_col = (clip_box.right - orig_x) / width; - if (clip_box.right <= orig_x) - max_col--; - - min_row = (clip_box.top - orig_y) / height; - if (clip_box.top < orig_y) - min_row--; - - max_row = (clip_box.bottom - orig_y) / height; - if (clip_box.bottom <= orig_y) - max_row--; - } - float left_offset = cell_bbox.left - mtPattern2Device.e; - float top_offset = cell_bbox.bottom - mtPattern2Device.f; - RetainPtr<CFX_DIBitmap> pPatternBitmap; - if (width * height < 16) { - RetainPtr<CFX_DIBitmap> pEnlargedBitmap = DrawPatternBitmap( - m_pContext->GetDocument(), m_pContext->GetPageCache(), pPattern, - pPatternForm.get(), mtObj2Device, 8, 8, m_Options.GetOptions()); - pPatternBitmap = pEnlargedBitmap->StretchTo( - width, height, FXDIB_ResampleOptions(), nullptr); - } else { - pPatternBitmap = - DrawPatternBitmap(m_pContext->GetDocument(), m_pContext->GetPageCache(), - pPattern, pPatternForm.get(), mtObj2Device, width, - height, m_Options.GetOptions()); - } - if (!pPatternBitmap) - return; - - if (m_Options.ColorModeIs(CPDF_RenderOptions::kGray)) - pPatternBitmap->ConvertColorScale(0, 0xffffff); - - FX_ARGB fill_argb = GetFillArgb(pPageObj); - int clip_width = clip_box.right - clip_box.left; - int clip_height = clip_box.bottom - clip_box.top; - auto pScreen = pdfium::MakeRetain<CFX_DIBitmap>(); - if (!pScreen->Create(clip_width, clip_height, FXDIB_Argb)) - return; - - pScreen->Clear(0); - const uint8_t* const src_buf = pPatternBitmap->GetBuffer(); - for (int col = min_col; col <= max_col; col++) { - for (int row = min_row; row <= max_row; row++) { - int start_x; - int start_y; - if (bAligned) { - start_x = - FXSYS_roundf(mtPattern2Device.e) + col * width - clip_box.left; - start_y = - FXSYS_roundf(mtPattern2Device.f) + row * height - clip_box.top; - } else { - CFX_PointF original = mtPattern2Device.Transform( - CFX_PointF(col * pPattern->x_step(), row * pPattern->y_step())); - - pdfium::base::CheckedNumeric<int> safeStartX = - FXSYS_roundf(original.x + left_offset); - pdfium::base::CheckedNumeric<int> safeStartY = - FXSYS_roundf(original.y + top_offset); - - safeStartX -= clip_box.left; - safeStartY -= clip_box.top; - if (!safeStartX.IsValid() || !safeStartY.IsValid()) - return; - - start_x = safeStartX.ValueOrDie(); - start_y = safeStartY.ValueOrDie(); - } - if (width == 1 && height == 1) { - if (start_x < 0 || start_x >= clip_box.Width() || start_y < 0 || - start_y >= clip_box.Height()) { - continue; - } - uint32_t* dest_buf = reinterpret_cast<uint32_t*>( - pScreen->GetBuffer() + pScreen->GetPitch() * start_y + start_x * 4); - if (pPattern->colored()) { - const auto* src_buf32 = reinterpret_cast<const uint32_t*>(src_buf); - *dest_buf = *src_buf32; - } else { - *dest_buf = (*src_buf << 24) | (fill_argb & 0xffffff); - } - } else { - if (pPattern->colored()) { - pScreen->CompositeBitmap(start_x, start_y, width, height, - pPatternBitmap, 0, 0, BlendMode::kNormal, - nullptr, false); - } else { - pScreen->CompositeMask(start_x, start_y, width, height, - pPatternBitmap, fill_argb, 0, 0, - BlendMode::kNormal, nullptr, false); - } - } - } - } CompositeDIBitmap(pScreen, clip_box.left, clip_box.top, 0, 255, BlendMode::kNormal, CPDF_Transparency()); } -void CPDF_RenderStatus::DrawPathWithPattern(CPDF_PathObject* pPathObj, +void CPDF_RenderStatus::DrawPathWithPattern(CPDF_PathObject* path_obj, const CFX_Matrix& mtObj2Device, const CPDF_Color* pColor, - bool bStroke) { - CPDF_Pattern* pattern = pColor->GetPattern(); + bool stroke) { + RetainPtr<CPDF_Pattern> pattern = pColor->GetPattern(); if (!pattern) return; if (CPDF_TilingPattern* pTilingPattern = pattern->AsTilingPattern()) - DrawTilingPattern(pTilingPattern, pPathObj, mtObj2Device, bStroke); + DrawTilingPattern(pTilingPattern, path_obj, mtObj2Device, stroke); else if (CPDF_ShadingPattern* pShadingPattern = pattern->AsShadingPattern()) - DrawShadingPattern(pShadingPattern, pPathObj, mtObj2Device, bStroke); + DrawShadingPattern(pShadingPattern, path_obj, mtObj2Device, stroke); } -void CPDF_RenderStatus::ProcessPathPattern(CPDF_PathObject* pPathObj, - const CFX_Matrix& mtObj2Device, - int* filltype, - bool* bStroke) { - ASSERT(filltype); - ASSERT(bStroke); +void CPDF_RenderStatus::ProcessPathPattern( + CPDF_PathObject* path_obj, + const CFX_Matrix& mtObj2Device, + CFX_FillRenderOptions::FillType* fill_type, + bool* stroke) { + DCHECK(fill_type); + DCHECK(stroke); - if (*filltype) { - const CPDF_Color& FillColor = *pPathObj->m_ColorState.GetFillColor(); + if (*fill_type != CFX_FillRenderOptions::FillType::kNoFill) { + const CPDF_Color& FillColor = *path_obj->m_ColorState.GetFillColor(); if (FillColor.IsPattern()) { - DrawPathWithPattern(pPathObj, mtObj2Device, &FillColor, false); - *filltype = 0; + DrawPathWithPattern(path_obj, mtObj2Device, &FillColor, false); + *fill_type = CFX_FillRenderOptions::FillType::kNoFill; } } - if (*bStroke) { - const CPDF_Color& StrokeColor = *pPathObj->m_ColorState.GetStrokeColor(); + if (*stroke) { + const CPDF_Color& StrokeColor = *path_obj->m_ColorState.GetStrokeColor(); if (StrokeColor.IsPattern()) { - DrawPathWithPattern(pPathObj, mtObj2Device, &StrokeColor, true); - *bStroke = false; + DrawPathWithPattern(path_obj, mtObj2Device, &StrokeColor, true); + *stroke = false; } } } bool CPDF_RenderStatus::ProcessImage(CPDF_ImageObject* pImageObj, const CFX_Matrix& mtObj2Device) { - CPDF_ImageRenderer render; - if (render.Start(this, pImageObj, mtObj2Device, m_bStdCS, m_curBlend)) + CPDF_ImageRenderer render(this); + if (render.Start(pImageObj, mtObj2Device, m_bStdCS, m_curBlend)) render.Continue(nullptr); return render.GetResult(); } @@ -1460,21 +1201,21 @@ return; if (blend_mode == BlendMode::kNormal) { - if (!pDIBitmap->IsAlphaMask()) { + if (!pDIBitmap->IsMaskFormat()) { if (bitmap_alpha < 255) { -#ifdef _SKIA_SUPPORT_ - std::unique_ptr<CFX_ImageRenderer> dummy; - CFX_Matrix m = CFX_RenderDevice::GetFlipMatrix( - pDIBitmap->GetWidth(), pDIBitmap->GetHeight(), left, top); - m_pDevice->StartDIBits(pDIBitmap, bitmap_alpha, 0, m, - FXDIB_ResampleOptions(), &dummy); - return; -#else + if (CFX_DefaultRenderDevice::SkiaIsDefaultRenderer()) { + std::unique_ptr<CFX_ImageRenderer> dummy; + CFX_Matrix m = CFX_RenderDevice::GetFlipMatrix( + pDIBitmap->GetWidth(), pDIBitmap->GetHeight(), left, top); + m_pDevice->StartDIBits(pDIBitmap, bitmap_alpha, 0, m, + FXDIB_ResampleOptions(), &dummy); + return; + } pDIBitmap->MultiplyAlpha(bitmap_alpha); -#endif } -#ifdef _SKIA_SUPPORT_ - CFX_SkiaDeviceDriver::PreMultiply(pDIBitmap); +#if defined(_SKIA_SUPPORT_) + if (CFX_DefaultRenderDevice::SkiaIsDefaultRenderer()) + pDIBitmap->PreMultiply(); #endif if (m_pDevice->SetDIBits(pDIBitmap, left, top)) { return; @@ -1499,7 +1240,7 @@ (m_pDevice->GetRenderCaps() & FXRC_GET_BITS) && !bBackAlphaRequired); if (bGetBackGround) { if (bIsolated || !transparency.IsGroup()) { - if (!pDIBitmap->IsAlphaMask()) + if (!pDIBitmap->IsMaskFormat()) m_pDevice->SetDIBitsWithBlend(pDIBitmap, left, top, blend_mode); return; } @@ -1509,7 +1250,7 @@ rect.Intersect(m_pDevice->GetClipBox()); RetainPtr<CFX_DIBitmap> pClone; if (m_pDevice->GetBackDrop() && m_pDevice->GetBitmap()) { - pClone = m_pDevice->GetBackDrop()->Clone(&rect); + pClone = m_pDevice->GetBackDrop()->ClipTo(rect); if (!pClone) return; @@ -1519,7 +1260,7 @@ BlendMode::kNormal, nullptr, false); left = std::min(left, 0); top = std::min(top, 0); - if (pDIBitmap->IsAlphaMask()) { + if (pDIBitmap->IsMaskFormat()) { pClone->CompositeMask(0, 0, pClone->GetWidth(), pClone->GetHeight(), pDIBitmap, mask_argb, left, top, blend_mode, nullptr, false); @@ -1534,124 +1275,116 @@ if (m_pDevice->GetBackDrop()) { m_pDevice->SetDIBits(pClone, rect.left, rect.top); } else { - if (!pDIBitmap->IsAlphaMask()) { + if (!pDIBitmap->IsMaskFormat()) { m_pDevice->SetDIBitsWithBlend(pDIBitmap, rect.left, rect.top, blend_mode); } } return; } - int back_left; - int back_top; - FX_RECT rect(left, top, left + pDIBitmap->GetWidth(), - top + pDIBitmap->GetHeight()); + FX_RECT bbox = GetClippedBBox(FX_RECT(left, top, left + pDIBitmap->GetWidth(), + top + pDIBitmap->GetHeight())); RetainPtr<CFX_DIBitmap> pBackdrop = GetBackdrop( - m_pCurObj.Get(), rect, blend_mode != BlendMode::kNormal && bIsolated, - &back_left, &back_top); + m_pCurObj, bbox, blend_mode != BlendMode::kNormal && bIsolated); if (!pBackdrop) return; - if (pDIBitmap->IsAlphaMask()) { - pBackdrop->CompositeMask(left - back_left, top - back_top, + if (pDIBitmap->IsMaskFormat()) { + pBackdrop->CompositeMask(left - bbox.left, top - bbox.top, pDIBitmap->GetWidth(), pDIBitmap->GetHeight(), pDIBitmap, mask_argb, 0, 0, blend_mode, nullptr, false); } else { - pBackdrop->CompositeBitmap(left - back_left, top - back_top, + pBackdrop->CompositeBitmap(left - bbox.left, top - bbox.top, pDIBitmap->GetWidth(), pDIBitmap->GetHeight(), pDIBitmap, 0, 0, blend_mode, nullptr, false); } auto pBackdrop1 = pdfium::MakeRetain<CFX_DIBitmap>(); pBackdrop1->Create(pBackdrop->GetWidth(), pBackdrop->GetHeight(), - FXDIB_Rgb32); + FXDIB_Format::kRgb32); pBackdrop1->Clear((uint32_t)-1); pBackdrop1->CompositeBitmap(0, 0, pBackdrop->GetWidth(), pBackdrop->GetHeight(), pBackdrop, 0, 0, BlendMode::kNormal, nullptr, false); pBackdrop = std::move(pBackdrop1); - m_pDevice->SetDIBits(pBackdrop, back_left, back_top); + m_pDevice->SetDIBits(pBackdrop, bbox.left, bbox.top); } RetainPtr<CFX_DIBitmap> CPDF_RenderStatus::LoadSMask( CPDF_Dictionary* pSMaskDict, FX_RECT* pClipRect, - const CFX_Matrix* pMatrix) { + const CFX_Matrix& mtMatrix) { if (!pSMaskDict) return nullptr; - CPDF_Stream* pGroup = pSMaskDict->GetStreamFor(pdfium::transparency::kG); + RetainPtr<CPDF_Stream> pGroup = + pSMaskDict->GetMutableStreamFor(pdfium::transparency::kG); if (!pGroup) return nullptr; std::unique_ptr<CPDF_Function> pFunc; - const CPDF_Object* pFuncObj = + RetainPtr<const CPDF_Object> pFuncObj = pSMaskDict->GetDirectObjectFor(pdfium::transparency::kTR); if (pFuncObj && (pFuncObj->IsDictionary() || pFuncObj->IsStream())) - pFunc = CPDF_Function::Load(pFuncObj); + pFunc = CPDF_Function::Load(std::move(pFuncObj)); - CFX_Matrix matrix = *pMatrix; + CFX_Matrix matrix = mtMatrix; matrix.Translate(-pClipRect->left, -pClipRect->top); - CPDF_Form form(m_pContext->GetDocument(), m_pContext->GetPageResources(), - pGroup); + CPDF_Form form(m_pContext->GetDocument(), + m_pContext->GetMutablePageResources(), pGroup); form.ParseContent(); CFX_DefaultRenderDevice bitmap_device; bool bLuminosity = - pSMaskDict->GetStringFor(pdfium::transparency::kSoftMaskSubType) != + pSMaskDict->GetByteStringFor(pdfium::transparency::kSoftMaskSubType) != pdfium::transparency::kAlpha; int width = pClipRect->right - pClipRect->left; int height = pClipRect->bottom - pClipRect->top; - FXDIB_Format format; -#if defined(OS_MACOSX) || defined _SKIA_SUPPORT_ || defined _SKIA_SUPPORT_PATHS_ - format = bLuminosity ? FXDIB_Rgb32 : FXDIB_8bppMask; -#else - format = bLuminosity ? FXDIB_Rgb : FXDIB_8bppMask; -#endif + FXDIB_Format format = GetFormatForLuminosity(bLuminosity); if (!bitmap_device.Create(width, height, format, nullptr)) return nullptr; RetainPtr<CFX_DIBitmap> bitmap = bitmap_device.GetBitmap(); - int nCSFamily = 0; + CPDF_ColorSpace::Family nCSFamily = CPDF_ColorSpace::Family::kUnknown; if (bLuminosity) { FX_ARGB back_color = - GetBackColor(pSMaskDict, pGroup->GetDict(), &nCSFamily); + GetBackColor(pSMaskDict, pGroup->GetDict().Get(), &nCSFamily); bitmap->Clear(back_color); } else { bitmap->Clear(0); } - const CPDF_Dictionary* pFormResource = + RetainPtr<const CPDF_Dictionary> pFormResource = form.GetDict()->GetDictFor("Resources"); CPDF_RenderOptions options; options.SetColorMode(bLuminosity ? CPDF_RenderOptions::kNormal : CPDF_RenderOptions::kAlpha); - CPDF_RenderStatus status(m_pContext.Get(), &bitmap_device); + CPDF_RenderStatus status(m_pContext, &bitmap_device); status.SetOptions(options); status.SetGroupFamily(nCSFamily); status.SetLoadMask(bLuminosity); status.SetStdCS(true); - status.SetFormResource(pFormResource); + status.SetFormResource(std::move(pFormResource)); status.SetDropObjects(m_bDropObjects); status.Initialize(nullptr, nullptr); status.RenderObjectList(&form, matrix); auto pMask = pdfium::MakeRetain<CFX_DIBitmap>(); - if (!pMask->Create(width, height, FXDIB_8bppMask)) + if (!pMask->Create(width, height, FXDIB_Format::k8bppMask)) return nullptr; - uint8_t* dest_buf = pMask->GetBuffer(); + pdfium::span<uint8_t> dest_buf = pMask->GetBuffer(); + pdfium::span<const uint8_t> src_buf = bitmap->GetBuffer(); int dest_pitch = pMask->GetPitch(); - uint8_t* src_buf = bitmap->GetBuffer(); int src_pitch = bitmap->GetPitch(); - std::vector<uint8_t> transfers(256); + DataVector<uint8_t> transfers(256); if (pFunc) { std::vector<float> results(pFunc->CountOutputs()); for (size_t i = 0; i < transfers.size(); ++i) { float input = i / 255.0f; - int nresult; - pFunc->Call(&input, 1, results.data(), &nresult); + pFunc->Call(pdfium::make_span(&input, 1), results); transfers[i] = FXSYS_roundf(results[0] * 255); } } else { @@ -1659,10 +1392,12 @@ std::iota(transfers.begin(), transfers.end(), 0); } if (bLuminosity) { - int Bpp = bitmap->GetBPP() / 8; + const int Bpp = bitmap->GetBPP() / 8; for (int row = 0; row < height; row++) { - uint8_t* dest_pos = dest_buf + row * dest_pitch; - uint8_t* src_pos = src_buf + row * src_pitch; + const size_t dest_offset = Fx2DSizeOrDie(row, dest_pitch); + const size_t src_offset = Fx2DSizeOrDie(row, src_pitch); + uint8_t* dest_pos = dest_buf.subspan(dest_offset).data(); + const uint8_t* src_pos = src_buf.subspan(src_offset).data(); for (int col = 0; col < width; col++) { *dest_pos++ = transfers[FXRGB2GRAY(src_pos[2], src_pos[1], *src_pos)]; src_pos += Bpp; @@ -1674,33 +1409,34 @@ dest_buf[i] = transfers[src_buf[i]]; } } else { - memcpy(dest_buf, src_buf, dest_pitch * height); + fxcrt::spancpy(dest_buf, src_buf.first(dest_pitch * height)); } return pMask; } FX_ARGB CPDF_RenderStatus::GetBackColor(const CPDF_Dictionary* pSMaskDict, const CPDF_Dictionary* pGroupDict, - int* pCSFamily) { + CPDF_ColorSpace::Family* pCSFamily) { static constexpr FX_ARGB kDefaultColor = ArgbEncode(255, 0, 0, 0); - const CPDF_Array* pBC = pSMaskDict->GetArrayFor(pdfium::transparency::kBC); + RetainPtr<const CPDF_Array> pBC = + pSMaskDict->GetArrayFor(pdfium::transparency::kBC); if (!pBC) return kDefaultColor; - const CPDF_Object* pCSObj = nullptr; - const CPDF_Dictionary* pGroup = + RetainPtr<const CPDF_Object> pCSObj; + RetainPtr<const CPDF_Dictionary> pGroup = pGroupDict ? pGroupDict->GetDictFor("Group") : nullptr; if (pGroup) pCSObj = pGroup->GetDirectObjectFor(pdfium::transparency::kCS); RetainPtr<CPDF_ColorSpace> pCS = CPDF_DocPageData::FromDocument(m_pContext->GetDocument()) - ->GetColorSpace(pCSObj, nullptr); + ->GetColorSpace(pCSObj.Get(), nullptr); if (!pCS) return kDefaultColor; - int family = pCS->GetFamily(); - if (family == PDFCS_LAB || pCS->IsSpecial() || - (family == PDFCS_ICCBASED && !pCS->IsNormal())) { + CPDF_ColorSpace::Family family = pCS->GetFamily(); + if (family == CPDF_ColorSpace::Family::kLab || pCS->IsSpecial() || + (family == CPDF_ColorSpace::Family::kICCBased && !pCS->IsNormal())) { return kDefaultColor; } @@ -1709,13 +1445,13 @@ uint32_t comps = std::max(8u, pCS->CountComponents()); size_t count = std::min<size_t>(8, pBC->size()); - std::vector<float> floats = ReadArrayElementsToVector(pBC, count); + std::vector<float> floats = ReadArrayElementsToVector(pBC.Get(), count); floats.resize(comps); float R; float G; float B; - pCS->GetRGB(floats.data(), &R, &G, &B); + pCS->GetRGB(floats, &R, &G, &B); return ArgbEncode(255, static_cast<int>(R * 255), static_cast<int>(G * 255), static_cast<int>(B * 255)); }
diff --git a/core/fpdfapi/render/cpdf_renderstatus.h b/core/fpdfapi/render/cpdf_renderstatus.h index 76eb71c..76596f0 100644 --- a/core/fpdfapi/render/cpdf_renderstatus.h +++ b/core/fpdfapi/render/cpdf_renderstatus.h
@@ -1,4 +1,4 @@ -// Copyright 2016 PDFium Authors. All rights reserved. +// Copyright 2016 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -8,24 +8,25 @@ #define CORE_FPDFAPI_RENDER_CPDF_RENDERSTATUS_H_ #include <memory> +#include <utility> #include <vector> #include "core/fpdfapi/page/cpdf_clippath.h" +#include "core/fpdfapi/page/cpdf_colorspace.h" #include "core/fpdfapi/page/cpdf_graphicstates.h" #include "core/fpdfapi/page/cpdf_transparency.h" #include "core/fpdfapi/parser/cpdf_dictionary.h" #include "core/fpdfapi/render/cpdf_renderoptions.h" #include "core/fxcrt/retain_ptr.h" #include "core/fxcrt/unowned_ptr.h" -#include "core/fxge/fx_dib.h" +#include "core/fxge/dib/fx_dib.h" class CFX_DIBitmap; -class CFX_PathData; +class CFX_Path; class CFX_RenderDevice; class CPDF_Color; class CPDF_Font; class CPDF_FormObject; -class CPDF_ImageCacheEntry; class CPDF_ImageObject; class CPDF_ImageRenderer; class CPDF_Object; @@ -37,7 +38,6 @@ class CPDF_ShadingPattern; class CPDF_TilingPattern; class CPDF_TransferFunc; -class CPDF_Type3Cache; class CPDF_Type3Char; class CPDF_Type3Font; class PauseIndicatorIface; @@ -51,15 +51,17 @@ void SetOptions(const CPDF_RenderOptions& options) { m_Options = options; } void SetDeviceMatrix(const CFX_Matrix& matrix) { m_DeviceMatrix = matrix; } void SetStopObject(const CPDF_PageObject* pStopObj) { m_pStopObj = pStopObj; } - void SetFormResource(const CPDF_Dictionary* pRes) { - m_pFormResource.Reset(pRes); + void SetFormResource(RetainPtr<const CPDF_Dictionary> pRes) { + m_pFormResource = std::move(pRes); } void SetType3Char(CPDF_Type3Char* pType3Char) { m_pType3Char = pType3Char; } void SetFillColor(FX_ARGB color) { m_T3FillColor = color; } void SetDropObjects(bool bDropObjects) { m_bDropObjects = bDropObjects; } void SetLoadMask(bool bLoadMask) { m_bLoadMask = bLoadMask; } void SetStdCS(bool bStdCS) { m_bStdCS = bStdCS; } - void SetGroupFamily(uint32_t family) { m_GroupFamily = family; } + void SetGroupFamily(CPDF_ColorSpace::Family family) { + m_GroupFamily = family; + } void SetTransparency(const CPDF_Transparency& transparency) { m_Transparency = transparency; } @@ -77,41 +79,39 @@ void ProcessClipPath(const CPDF_ClipPath& ClipPath, const CFX_Matrix& mtObj2Device); - uint32_t GetGroupFamily() const { return m_GroupFamily; } + CPDF_ColorSpace::Family GetGroupFamily() const { return m_GroupFamily; } bool GetLoadMask() const { return m_bLoadMask; } bool GetDropObjects() const { return m_bDropObjects; } bool IsPrint() const { return m_bPrint; } bool IsStopped() const { return m_bStopped; } - CPDF_RenderContext* GetContext() const { return m_pContext.Get(); } + CPDF_RenderContext* GetContext() const { return m_pContext; } const CPDF_Dictionary* GetFormResource() const { return m_pFormResource.Get(); } - CPDF_Dictionary* GetPageResource() const { return m_pPageResource.Get(); } + const CPDF_Dictionary* GetPageResource() const { + return m_pPageResource.Get(); + } CFX_RenderDevice* GetRenderDevice() const { return m_pDevice; } const CPDF_RenderOptions& GetRenderOptions() const { return m_Options; } -#if defined _SKIA_SUPPORT_ +#if defined(_SKIA_SUPPORT_) void DebugVerifyDeviceIsPreMultiplied() const; #endif RetainPtr<CPDF_TransferFunc> GetTransferFunc( - const CPDF_Object* pObject) const; + RetainPtr<const CPDF_Object> pObject) const; - FX_ARGB GetFillArgb(CPDF_PageObject* pObj) const { - return GetFillArgbInternal(pObj, false); - } - FX_ARGB GetFillArgbForType3(CPDF_PageObject* pObj) const { - return GetFillArgbInternal(pObj, true); - } + FX_ARGB GetFillArgb(CPDF_PageObject* pObj) const; + FX_ARGB GetFillArgbForType3(CPDF_PageObject* pObj) const; - void DrawTilingPattern(CPDF_TilingPattern* pPattern, + void DrawTilingPattern(CPDF_TilingPattern* pattern, CPDF_PageObject* pPageObj, const CFX_Matrix& mtObj2Device, - bool bStroke); - void DrawShadingPattern(CPDF_ShadingPattern* pPattern, + bool stroke); + void DrawShadingPattern(CPDF_ShadingPattern* pattern, const CPDF_PageObject* pPageObj, const CFX_Matrix& mtObj2Device, - bool bStroke); + bool stroke); void CompositeDIBitmap(const RetainPtr<CFX_DIBitmap>& pDIBitmap, int left, int top, @@ -120,12 +120,11 @@ BlendMode blend_mode, const CPDF_Transparency& transparency); - private: static std::unique_ptr<CPDF_GraphicStates> CloneObjStates( const CPDF_GraphicStates* pSrcStates, - bool bStroke); + bool stroke); - FX_ARGB GetFillArgbInternal(CPDF_PageObject* pObj, bool bType3) const; + private: bool ProcessTransparency(CPDF_PageObject* PageObj, const CFX_Matrix& mtObj2Device); void ProcessObjectNoClip(CPDF_PageObject* pObj, @@ -133,21 +132,21 @@ void DrawObjWithBackground(CPDF_PageObject* pObj, const CFX_Matrix& mtObj2Device); bool DrawObjWithBlend(CPDF_PageObject* pObj, const CFX_Matrix& mtObj2Device); - bool ProcessPath(CPDF_PathObject* pPathObj, const CFX_Matrix& mtObj2Device); - void ProcessPathPattern(CPDF_PathObject* pPathObj, + bool ProcessPath(CPDF_PathObject* path_obj, const CFX_Matrix& mtObj2Device); + void ProcessPathPattern(CPDF_PathObject* path_obj, const CFX_Matrix& mtObj2Device, - int* filltype, - bool* bStroke); - void DrawPathWithPattern(CPDF_PathObject* pPathObj, + CFX_FillRenderOptions::FillType* fill_type, + bool* stroke); + void DrawPathWithPattern(CPDF_PathObject* path_obj, const CFX_Matrix& mtObj2Device, const CPDF_Color* pColor, - bool bStroke); - bool ClipPattern(const CPDF_PageObject* pPageObj, + bool stroke); + bool ClipPattern(const CPDF_PageObject* page_obj, const CFX_Matrix& mtObj2Device, - bool bStroke); - bool SelectClipPath(const CPDF_PathObject* pPathObj, + bool stroke); + bool SelectClipPath(const CPDF_PathObject* path_obj, const CFX_Matrix& mtObj2Device, - bool bStroke); + bool stroke); bool ProcessImage(CPDF_ImageObject* pImageObj, const CFX_Matrix& mtObj2Device); void ProcessShading(const CPDF_ShadingObject* pShadingObj, @@ -156,52 +155,51 @@ const CFX_Matrix& mtObj2Device); bool ProcessText(CPDF_TextObject* textobj, const CFX_Matrix& mtObj2Device, - CFX_PathData* pClippingPath); + CFX_Path* clipping_path); void DrawTextPathWithPattern(const CPDF_TextObject* textobj, const CFX_Matrix& mtObj2Device, CPDF_Font* pFont, float font_size, - const CFX_Matrix* pTextMatrix, - bool bFill, - bool bStroke); + const CFX_Matrix& mtTextMatrix, + bool fill, + bool stroke); bool ProcessForm(const CPDF_FormObject* pFormObj, const CFX_Matrix& mtObj2Device); + FX_RECT GetClippedBBox(const FX_RECT& rect) const; RetainPtr<CFX_DIBitmap> GetBackdrop(const CPDF_PageObject* pObj, - const FX_RECT& rect, - bool bBackAlphaRequired, - int* left, - int* top); + const FX_RECT& bbox, + bool bBackAlphaRequired); RetainPtr<CFX_DIBitmap> LoadSMask(CPDF_Dictionary* pSMaskDict, FX_RECT* pClipRect, - const CFX_Matrix* pMatrix); + const CFX_Matrix& mtMatrix); // Optionally write the colorspace family value into |pCSFamily|. FX_ARGB GetBackColor(const CPDF_Dictionary* pSMaskDict, const CPDF_Dictionary* pGroupDict, - int* pCSFamily); + CPDF_ColorSpace::Family* pCSFamily); FX_ARGB GetStrokeArgb(CPDF_PageObject* pObj) const; FX_RECT GetObjectClippedRect(const CPDF_PageObject* pObj, const CFX_Matrix& mtObj2Device) const; CPDF_RenderOptions m_Options; RetainPtr<const CPDF_Dictionary> m_pFormResource; - RetainPtr<CPDF_Dictionary> m_pPageResource; - std::vector<CPDF_Type3Font*> m_Type3FontCache; + RetainPtr<const CPDF_Dictionary> m_pPageResource; + std::vector<UnownedPtr<const CPDF_Type3Font>> m_Type3FontCache; UnownedPtr<CPDF_RenderContext> const m_pContext; - bool m_bStopped = false; - CFX_RenderDevice* const m_pDevice; + UnownedPtr<CFX_RenderDevice> const m_pDevice; CFX_Matrix m_DeviceMatrix; CPDF_ClipPath m_LastClipPath; UnownedPtr<const CPDF_PageObject> m_pCurObj; UnownedPtr<const CPDF_PageObject> m_pStopObj; CPDF_GraphicStates m_InitialStates; std::unique_ptr<CPDF_ImageRenderer> m_pImageRenderer; + UnownedPtr<const CPDF_Type3Char> m_pType3Char; CPDF_Transparency m_Transparency; + bool m_bStopped = false; bool m_bPrint = false; bool m_bDropObjects = false; bool m_bStdCS = false; bool m_bLoadMask = false; - uint32_t m_GroupFamily = 0; - UnownedPtr<CPDF_Type3Char> m_pType3Char; + CPDF_ColorSpace::Family m_GroupFamily = CPDF_ColorSpace::Family::kUnknown; FX_ARGB m_T3FillColor = 0; BlendMode m_curBlend = BlendMode::kNormal; };
diff --git a/core/fpdfapi/render/cpdf_rendertiling.cpp b/core/fpdfapi/render/cpdf_rendertiling.cpp new file mode 100644 index 0000000..fcde2b2 --- /dev/null +++ b/core/fpdfapi/render/cpdf_rendertiling.cpp
@@ -0,0 +1,250 @@ +// Copyright 2020 The PDFium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com + +#include "core/fpdfapi/render/cpdf_rendertiling.h" + +#include <limits> +#include <memory> + +#include "core/fpdfapi/page/cpdf_form.h" +#include "core/fpdfapi/page/cpdf_pageimagecache.h" +#include "core/fpdfapi/page/cpdf_tilingpattern.h" +#include "core/fpdfapi/parser/cpdf_document.h" +#include "core/fpdfapi/render/cpdf_rendercontext.h" +#include "core/fpdfapi/render/cpdf_renderoptions.h" +#include "core/fpdfapi/render/cpdf_renderstatus.h" +#include "core/fxcrt/fx_safe_types.h" +#include "core/fxge/cfx_defaultrenderdevice.h" + +namespace { + +RetainPtr<CFX_DIBitmap> DrawPatternBitmap( + CPDF_Document* pDoc, + CPDF_PageImageCache* pCache, + CPDF_TilingPattern* pPattern, + CPDF_Form* pPatternForm, + const CFX_Matrix& mtObject2Device, + int width, + int height, + const CPDF_RenderOptions::Options& draw_options) { + auto pBitmap = pdfium::MakeRetain<CFX_DIBitmap>(); + if (!pBitmap->Create(width, height, + pPattern->colored() ? FXDIB_Format::kArgb + : FXDIB_Format::k8bppMask)) { + return nullptr; + } + CFX_DefaultRenderDevice bitmap_device; + bitmap_device.AttachWithBackdropAndGroupKnockout( + pBitmap, /*pBackdropBitmap=*/nullptr, /*bGroupKnockout=*/true); + CFX_FloatRect cell_bbox = + pPattern->pattern_to_form().TransformRect(pPattern->bbox()); + cell_bbox = mtObject2Device.TransformRect(cell_bbox); + CFX_FloatRect bitmap_rect(0.0f, 0.0f, width, height); + CFX_Matrix mtAdjust; + mtAdjust.MatchRect(bitmap_rect, cell_bbox); + + CFX_Matrix mtPattern2Bitmap = mtObject2Device * mtAdjust; + CPDF_RenderOptions options; + if (!pPattern->colored()) + options.SetColorMode(CPDF_RenderOptions::kAlpha); + + options.GetOptions() = draw_options; + options.GetOptions().bForceHalftone = true; + + CPDF_RenderContext context(pDoc, nullptr, pCache); + context.AppendLayer(pPatternForm, mtPattern2Bitmap); + context.Render(&bitmap_device, nullptr, &options, nullptr); + +#if defined(_SKIA_SUPPORT_) + if (CFX_DefaultRenderDevice::SkiaIsDefaultRenderer()) + pBitmap->UnPreMultiply(); +#endif // defined(_SKIA_SUPPORT_) + return pBitmap; +} + +} // namespace + +// static +RetainPtr<CFX_DIBitmap> CPDF_RenderTiling::Draw( + CPDF_RenderStatus* pRenderStatus, + CPDF_PageObject* pPageObj, + CPDF_TilingPattern* pPattern, + CPDF_Form* pPatternForm, + const CFX_Matrix& mtObj2Device, + const FX_RECT& clip_box, + bool bStroke) { + const CFX_Matrix mtPattern2Device = + pPattern->pattern_to_form() * mtObj2Device; + + CFX_FloatRect cell_bbox = mtPattern2Device.TransformRect(pPattern->bbox()); + + float ceil_height = std::ceil(cell_bbox.Height()); + float ceil_width = std::ceil(cell_bbox.Width()); + + // Validate the float will fit into the int when the conversion is done. + if (!pdfium::base::IsValueInRangeForNumericType<int>(ceil_height) || + !pdfium::base::IsValueInRangeForNumericType<int>(ceil_width)) { + return nullptr; + } + + int width = static_cast<int>(ceil_width); + int height = static_cast<int>(ceil_height); + if (width <= 0) + width = 1; + if (height <= 0) + height = 1; + + CFX_FloatRect clip_box_p = + mtPattern2Device.GetInverse().TransformRect(CFX_FloatRect(clip_box)); + int min_col = static_cast<int>( + ceil((clip_box_p.left - pPattern->bbox().right) / pPattern->x_step())); + int max_col = static_cast<int>( + floor((clip_box_p.right - pPattern->bbox().left) / pPattern->x_step())); + int min_row = static_cast<int>( + ceil((clip_box_p.bottom - pPattern->bbox().top) / pPattern->y_step())); + int max_row = static_cast<int>( + floor((clip_box_p.top - pPattern->bbox().bottom) / pPattern->y_step())); + + // Make sure we can fit the needed width * height into an int. + if (height > std::numeric_limits<int>::max() / width) + return nullptr; + + CFX_RenderDevice* pDevice = pRenderStatus->GetRenderDevice(); + CPDF_RenderContext* pContext = pRenderStatus->GetContext(); + const CPDF_RenderOptions& options = pRenderStatus->GetRenderOptions(); + if (width > clip_box.Width() || height > clip_box.Height() || + width * height > clip_box.Width() * clip_box.Height()) { + std::unique_ptr<CPDF_GraphicStates> pStates; + if (!pPattern->colored()) + pStates = CPDF_RenderStatus::CloneObjStates(pPageObj, bStroke); + + RetainPtr<const CPDF_Dictionary> pFormResource = + pPatternForm->GetDict()->GetDictFor("Resources"); + for (int col = min_col; col <= max_col; col++) { + for (int row = min_row; row <= max_row; row++) { + CFX_PointF original = mtPattern2Device.Transform( + CFX_PointF(col * pPattern->x_step(), row * pPattern->y_step())); + CFX_Matrix matrix = mtObj2Device; + matrix.Translate(original.x - mtPattern2Device.e, + original.y - mtPattern2Device.f); + CFX_RenderDevice::StateRestorer restorer2(pDevice); + CPDF_RenderStatus status(pContext, pDevice); + status.SetOptions(options); + status.SetTransparency(pPatternForm->GetTransparency()); + status.SetFormResource(pFormResource); + status.SetDropObjects(pRenderStatus->GetDropObjects()); + status.Initialize(pRenderStatus, pStates.get()); + status.RenderObjectList(pPatternForm, matrix); + } + } + return nullptr; + } + + bool bAligned = + pPattern->bbox().left == 0 && pPattern->bbox().bottom == 0 && + pPattern->bbox().right == pPattern->x_step() && + pPattern->bbox().top == pPattern->y_step() && + (mtPattern2Device.IsScaled() || mtPattern2Device.Is90Rotated()); + if (bAligned) { + int orig_x = FXSYS_roundf(mtPattern2Device.e); + int orig_y = FXSYS_roundf(mtPattern2Device.f); + min_col = (clip_box.left - orig_x) / width; + if (clip_box.left < orig_x) + min_col--; + + max_col = (clip_box.right - orig_x) / width; + if (clip_box.right <= orig_x) + max_col--; + + min_row = (clip_box.top - orig_y) / height; + if (clip_box.top < orig_y) + min_row--; + + max_row = (clip_box.bottom - orig_y) / height; + if (clip_box.bottom <= orig_y) + max_row--; + } + float left_offset = cell_bbox.left - mtPattern2Device.e; + float top_offset = cell_bbox.bottom - mtPattern2Device.f; + RetainPtr<CFX_DIBitmap> pPatternBitmap; + if (width * height < 16) { + RetainPtr<CFX_DIBitmap> pEnlargedBitmap = DrawPatternBitmap( + pContext->GetDocument(), pContext->GetPageCache(), pPattern, + pPatternForm, mtObj2Device, 8, 8, options.GetOptions()); + pPatternBitmap = pEnlargedBitmap->StretchTo( + width, height, FXDIB_ResampleOptions(), nullptr); + } else { + pPatternBitmap = DrawPatternBitmap( + pContext->GetDocument(), pContext->GetPageCache(), pPattern, + pPatternForm, mtObj2Device, width, height, options.GetOptions()); + } + if (!pPatternBitmap) + return nullptr; + + if (options.ColorModeIs(CPDF_RenderOptions::kGray)) + pPatternBitmap->ConvertColorScale(0, 0xffffff); + + FX_ARGB fill_argb = pRenderStatus->GetFillArgb(pPageObj); + int clip_width = clip_box.right - clip_box.left; + int clip_height = clip_box.bottom - clip_box.top; + auto pScreen = pdfium::MakeRetain<CFX_DIBitmap>(); + if (!pScreen->Create(clip_width, clip_height, FXDIB_Format::kArgb)) + return nullptr; + + pdfium::span<const uint8_t> src_buf = pPatternBitmap->GetBuffer(); + for (int col = min_col; col <= max_col; col++) { + for (int row = min_row; row <= max_row; row++) { + int start_x; + int start_y; + if (bAligned) { + start_x = + FXSYS_roundf(mtPattern2Device.e) + col * width - clip_box.left; + start_y = + FXSYS_roundf(mtPattern2Device.f) + row * height - clip_box.top; + } else { + CFX_PointF original = mtPattern2Device.Transform( + CFX_PointF(col * pPattern->x_step(), row * pPattern->y_step())); + + FX_SAFE_INT32 safeStartX = FXSYS_roundf(original.x + left_offset); + FX_SAFE_INT32 safeStartY = FXSYS_roundf(original.y + top_offset); + + safeStartX -= clip_box.left; + safeStartY -= clip_box.top; + if (!safeStartX.IsValid() || !safeStartY.IsValid()) + return nullptr; + + start_x = safeStartX.ValueOrDie(); + start_y = safeStartY.ValueOrDie(); + } + if (width == 1 && height == 1) { + if (start_x < 0 || start_x >= clip_box.Width() || start_y < 0 || + start_y >= clip_box.Height()) { + continue; + } + uint32_t* dest_buf = reinterpret_cast<uint32_t*>( + pScreen->GetWritableScanline(start_y).subspan(start_x * 4).data()); + if (pPattern->colored()) { + const auto* src_buf32 = + reinterpret_cast<const uint32_t*>(src_buf.data()); + *dest_buf = *src_buf32; + } else { + *dest_buf = (*(src_buf.data()) << 24) | (fill_argb & 0xffffff); + } + } else { + if (pPattern->colored()) { + pScreen->CompositeBitmap(start_x, start_y, width, height, + pPatternBitmap, 0, 0, BlendMode::kNormal, + nullptr, false); + } else { + pScreen->CompositeMask(start_x, start_y, width, height, + pPatternBitmap, fill_argb, 0, 0, + BlendMode::kNormal, nullptr, false); + } + } + } + } + return pScreen; +}
diff --git a/core/fpdfapi/render/cpdf_rendertiling.h b/core/fpdfapi/render/cpdf_rendertiling.h new file mode 100644 index 0000000..b687f74 --- /dev/null +++ b/core/fpdfapi/render/cpdf_rendertiling.h
@@ -0,0 +1,35 @@ +// Copyright 2020 The PDFium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com + +#ifndef CORE_FPDFAPI_RENDER_CPDF_RENDERTILING_H_ +#define CORE_FPDFAPI_RENDER_CPDF_RENDERTILING_H_ + +#include "core/fxcrt/retain_ptr.h" +#include "core/fxge/dib/cfx_dibitmap.h" + +class CFX_Matrix; +class CPDF_Form; +class CPDF_PageObject; +class CPDF_RenderStatus; +class CPDF_TilingPattern; +struct FX_RECT; + +class CPDF_RenderTiling { + public: + static RetainPtr<CFX_DIBitmap> Draw(CPDF_RenderStatus* pRenderStatus, + CPDF_PageObject* pPageObj, + CPDF_TilingPattern* pPattern, + CPDF_Form* pPatternForm, + const CFX_Matrix& mtObj2Device, + const FX_RECT& clip_box, + bool bStroke); + + CPDF_RenderTiling() = delete; + CPDF_RenderTiling(const CPDF_RenderTiling&) = delete; + CPDF_RenderTiling& operator=(const CPDF_RenderTiling&) = delete; +}; + +#endif // CORE_FPDFAPI_RENDER_CPDF_RENDERTILING_H_
diff --git a/core/fpdfapi/render/cpdf_scaledrenderbuffer.cpp b/core/fpdfapi/render/cpdf_scaledrenderbuffer.cpp index 8536b3b..26e8b7f 100644 --- a/core/fpdfapi/render/cpdf_scaledrenderbuffer.cpp +++ b/core/fpdfapi/render/cpdf_scaledrenderbuffer.cpp
@@ -1,4 +1,4 @@ -// Copyright 2016 PDFium Authors. All rights reserved. +// Copyright 2016 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -6,11 +6,11 @@ #include "core/fpdfapi/render/cpdf_scaledrenderbuffer.h" +#include "core/fpdfapi/parser/cpdf_dictionary.h" #include "core/fpdfapi/render/cpdf_devicebuffer.h" #include "core/fpdfapi/render/cpdf_rendercontext.h" #include "core/fxge/cfx_defaultrenderdevice.h" #include "core/fxge/dib/cfx_dibitmap.h" -#include "third_party/base/ptr_util.h" namespace { @@ -18,9 +18,9 @@ } // namespace -CPDF_ScaledRenderBuffer::CPDF_ScaledRenderBuffer() {} +CPDF_ScaledRenderBuffer::CPDF_ScaledRenderBuffer() = default; -CPDF_ScaledRenderBuffer::~CPDF_ScaledRenderBuffer() {} +CPDF_ScaledRenderBuffer::~CPDF_ScaledRenderBuffer() = default; bool CPDF_ScaledRenderBuffer::Initialize(CPDF_RenderContext* pContext, CFX_RenderDevice* pDevice, @@ -32,41 +32,39 @@ if (m_pDevice->GetDeviceCaps(FXDC_RENDER_CAPS) & FXRC_GET_BITS) return true; - m_pContext = pContext; m_Rect = rect; - m_pObject = pObj; m_Matrix = CPDF_DeviceBuffer::CalculateMatrix(pDevice, rect, max_dpi, /*scale=*/true); - m_pBitmapDevice = pdfium::MakeUnique<CFX_DefaultRenderDevice>(); + m_pBitmapDevice = std::make_unique<CFX_DefaultRenderDevice>(); bool bIsAlpha = !!(m_pDevice->GetDeviceCaps(FXDC_RENDER_CAPS) & FXRC_ALPHA_OUTPUT); - FXDIB_Format dibFormat = bIsAlpha ? FXDIB_Argb : FXDIB_Rgb; - while (1) { + FXDIB_Format dibFormat = bIsAlpha ? FXDIB_Format::kArgb : FXDIB_Format::kRgb; + while (true) { FX_RECT bitmap_rect = m_Matrix.TransformRect(CFX_FloatRect(rect)).GetOuterRect(); int32_t width = bitmap_rect.Width(); int32_t height = bitmap_rect.Height(); // Set to 0 to make CalculatePitchAndSize() calculate it. - uint32_t pitch = 0; - uint32_t size; - if (!CFX_DIBitmap::CalculatePitchAndSize(width, height, dibFormat, &pitch, - &size)) { + constexpr uint32_t kNoPitch = 0; + absl::optional<CFX_DIBitmap::PitchAndSize> pitch_size = + CFX_DIBitmap::CalculatePitchAndSize(width, height, dibFormat, kNoPitch); + if (!pitch_size.has_value()) return false; - } - if (size <= kImageSizeLimitBytes && + if (pitch_size.value().size <= kImageSizeLimitBytes && m_pBitmapDevice->Create(width, height, dibFormat, nullptr)) { break; } m_Matrix.Scale(0.5f, 0.5f); } - m_pContext->GetBackground(m_pBitmapDevice->GetBitmap(), m_pObject.Get(), - pOptions, m_Matrix); + pContext->GetBackground(m_pBitmapDevice->GetBitmap(), pObj, pOptions, + m_Matrix); return true; } CFX_RenderDevice* CPDF_ScaledRenderBuffer::GetDevice() const { - return m_pBitmapDevice ? m_pBitmapDevice.get() : m_pDevice.Get(); + return m_pBitmapDevice ? static_cast<CFX_RenderDevice*>(m_pBitmapDevice.get()) + : m_pDevice.get(); } void CPDF_ScaledRenderBuffer::OutputToDevice() {
diff --git a/core/fpdfapi/render/cpdf_scaledrenderbuffer.h b/core/fpdfapi/render/cpdf_scaledrenderbuffer.h index 0e7ac07..3fb9c0b 100644 --- a/core/fpdfapi/render/cpdf_scaledrenderbuffer.h +++ b/core/fpdfapi/render/cpdf_scaledrenderbuffer.h
@@ -1,4 +1,4 @@ -// Copyright 2016 PDFium Authors. All rights reserved. +// Copyright 2016 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -36,10 +36,8 @@ private: UnownedPtr<CFX_RenderDevice> m_pDevice; - UnownedPtr<CPDF_RenderContext> m_pContext; - FX_RECT m_Rect; - UnownedPtr<const CPDF_PageObject> m_pObject; std::unique_ptr<CFX_DefaultRenderDevice> m_pBitmapDevice; + FX_RECT m_Rect; CFX_Matrix m_Matrix; };
diff --git a/core/fpdfapi/render/cpdf_textrenderer.cpp b/core/fpdfapi/render/cpdf_textrenderer.cpp index fe1d258..e1a2acb 100644 --- a/core/fpdfapi/render/cpdf_textrenderer.cpp +++ b/core/fpdfapi/render/cpdf_textrenderer.cpp
@@ -1,4 +1,4 @@ -// Copyright 2016 PDFium Authors. All rights reserved. +// Copyright 2016 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -7,13 +7,15 @@ #include "core/fpdfapi/render/cpdf_textrenderer.h" #include <algorithm> +#include <vector> #include "core/fpdfapi/font/cpdf_font.h" -#include "core/fpdfapi/render/cpdf_charposlist.h" +#include "core/fpdfapi/render/charposlist.h" #include "core/fpdfapi/render/cpdf_renderoptions.h" #include "core/fxge/cfx_graphstatedata.h" -#include "core/fxge/cfx_pathdata.h" +#include "core/fxge/cfx_path.h" #include "core/fxge/cfx_renderdevice.h" +#include "core/fxge/cfx_textrenderoptions.h" #include "core/fxge/fx_font.h" #include "core/fxge/text_char_pos.h" @@ -23,23 +25,43 @@ return position == -1 ? pFont->GetFont() : pFont->GetFontFallback(position); } +CFX_TextRenderOptions GetTextRenderOptionsHelper( + const CPDF_Font* pFont, + const CPDF_RenderOptions& options) { + CFX_TextRenderOptions text_options; + + if (pFont->IsCIDFont()) + text_options.font_is_cid = true; + + if (options.GetOptions().bNoTextSmooth) + text_options.aliasing_type = CFX_TextRenderOptions::kAliasing; + else if (options.GetOptions().bClearType) + text_options.aliasing_type = CFX_TextRenderOptions::kLcd; + + if (options.GetOptions().bNoNativeText) + text_options.native_text = false; + + return text_options; +} + } // namespace // static -bool CPDF_TextRenderer::DrawTextPath(CFX_RenderDevice* pDevice, - const std::vector<uint32_t>& charCodes, - const std::vector<float>& charPos, - CPDF_Font* pFont, - float font_size, - const CFX_Matrix& mtText2User, - const CFX_Matrix* pUser2Device, - const CFX_GraphStateData* pGraphState, - FX_ARGB fill_argb, - FX_ARGB stroke_argb, - CFX_PathData* pClippingPath, - int nFlag) { - const CPDF_CharPosList CharPosList(charCodes, charPos, pFont, font_size); - const std::vector<TextCharPos>& pos = CharPosList.Get(); +bool CPDF_TextRenderer::DrawTextPath( + CFX_RenderDevice* pDevice, + pdfium::span<const uint32_t> char_codes, + pdfium::span<const float> char_pos, + CPDF_Font* pFont, + float font_size, + const CFX_Matrix& mtText2User, + const CFX_Matrix* pUser2Device, + const CFX_GraphStateData* pGraphState, + FX_ARGB fill_argb, + FX_ARGB stroke_argb, + CFX_Path* pClippingPath, + const CFX_FillRenderOptions& fill_options) { + std::vector<TextCharPos> pos = + GetCharPosList(char_codes, char_pos, pFont, font_size); if (pos.empty()) return true; @@ -52,19 +74,20 @@ continue; CFX_Font* font = GetFont(pFont, fontPosition); - if (!pDevice->DrawTextPath(i - startIndex, &pos[startIndex], font, - font_size, mtText2User, pUser2Device, - pGraphState, fill_argb, stroke_argb, - pClippingPath, nFlag)) { + if (!pDevice->DrawTextPath( + pdfium::make_span(pos).subspan(startIndex, i - startIndex), font, + font_size, mtText2User, pUser2Device, pGraphState, fill_argb, + stroke_argb, pClippingPath, fill_options)) { bDraw = false; } fontPosition = curFontPosition; startIndex = i; } CFX_Font* font = GetFont(pFont, fontPosition); - if (!pDevice->DrawTextPath(pos.size() - startIndex, &pos[startIndex], font, + if (!pDevice->DrawTextPath(pdfium::make_span(pos).subspan(startIndex), font, font_size, mtText2User, pUser2Device, pGraphState, - fill_argb, stroke_argb, pClippingPath, nFlag)) { + fill_argb, stroke_argb, pClippingPath, + fill_options)) { bDraw = false; } return bDraw; @@ -83,8 +106,8 @@ if (pFont->IsType3Font()) return; - int nChars = pFont->CountChar(str.AsStringView()); - if (nChars <= 0) + size_t nChars = pFont->CountChar(str.AsStringView()); + if (nChars == 0) return; size_t offset = 0; @@ -93,7 +116,7 @@ codes.resize(nChars); positions.resize(nChars - 1); float cur_pos = 0; - for (int i = 0; i < nChars; i++) { + for (size_t i = 0; i < nChars; i++) { codes[i] = pFont->GetNextChar(str.AsStringView(), &offset); if (i) positions[i - 1] = cur_pos; @@ -108,36 +131,20 @@ // static bool CPDF_TextRenderer::DrawNormalText(CFX_RenderDevice* pDevice, - const std::vector<uint32_t>& charCodes, - const std::vector<float>& charPos, + pdfium::span<const uint32_t> char_codes, + pdfium::span<const float> char_pos, CPDF_Font* pFont, float font_size, const CFX_Matrix& mtText2Device, FX_ARGB fill_argb, const CPDF_RenderOptions& options) { - const CPDF_CharPosList CharPosList(charCodes, charPos, pFont, font_size); - const std::vector<TextCharPos>& pos = CharPosList.Get(); + std::vector<TextCharPos> pos = + GetCharPosList(char_codes, char_pos, pFont, font_size); if (pos.empty()) return true; - int fxge_flags = 0; - if (options.GetOptions().bClearType) { - fxge_flags |= FXTEXT_CLEARTYPE; - if (options.GetOptions().bBGRStripe) - fxge_flags |= FXTEXT_BGR_STRIPE; - } - if (options.GetOptions().bNoTextSmooth) - fxge_flags |= FXTEXT_NOSMOOTH; - if (options.GetOptions().bPrintGraphicText) - fxge_flags |= FXTEXT_PRINTGRAPHICTEXT; - if (options.GetOptions().bNoNativeText) - fxge_flags |= FXTEXT_NO_NATIVETEXT; - if (options.GetOptions().bPrintImageText) - fxge_flags |= FXTEXT_PRINTIMAGETEXT; - - if (pFont->IsCIDFont()) - fxge_flags |= FXFONT_CIDFONT; - + CFX_TextRenderOptions text_options = + GetTextRenderOptionsHelper(pFont, options); bool bDraw = true; int32_t fontPosition = pos[0].m_FallbackFontPosition; size_t startIndex = 0; @@ -147,18 +154,18 @@ continue; CFX_Font* font = GetFont(pFont, fontPosition); - if (!pDevice->DrawNormalText(i - startIndex, &pos[startIndex], font, - font_size, mtText2Device, fill_argb, - fxge_flags)) { + if (!pDevice->DrawNormalText( + pdfium::make_span(pos).subspan(startIndex, i - startIndex), font, + font_size, mtText2Device, fill_argb, text_options)) { bDraw = false; } fontPosition = curFontPosition; startIndex = i; } CFX_Font* font = GetFont(pFont, fontPosition); - if (!pDevice->DrawNormalText(pos.size() - startIndex, &pos[startIndex], font, + if (!pDevice->DrawNormalText(pdfium::make_span(pos).subspan(startIndex), font, font_size, mtText2Device, fill_argb, - fxge_flags)) { + text_options)) { bDraw = false; } return bDraw;
diff --git a/core/fpdfapi/render/cpdf_textrenderer.h b/core/fpdfapi/render/cpdf_textrenderer.h index 91ab4cc..b5529a6 100644 --- a/core/fpdfapi/render/cpdf_textrenderer.h +++ b/core/fpdfapi/render/cpdf_textrenderer.h
@@ -1,4 +1,4 @@ -// Copyright 2016 PDFium Authors. All rights reserved. +// Copyright 2016 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -7,18 +7,19 @@ #ifndef CORE_FPDFAPI_RENDER_CPDF_TEXTRENDERER_H_ #define CORE_FPDFAPI_RENDER_CPDF_TEXTRENDERER_H_ -#include <vector> +#include <stdint.h> +#include "core/fxcrt/bytestring.h" #include "core/fxcrt/fx_coordinates.h" -#include "core/fxcrt/fx_string.h" -#include "core/fxcrt/fx_system.h" -#include "core/fxge/fx_dib.h" +#include "core/fxge/dib/fx_dib.h" +#include "third_party/base/span.h" class CFX_RenderDevice; class CFX_GraphStateData; -class CFX_PathData; +class CFX_Path; class CPDF_RenderOptions; class CPDF_Font; +struct CFX_FillRenderOptions; class CPDF_TextRenderer { public: @@ -33,8 +34,8 @@ const CPDF_RenderOptions& options); static bool DrawTextPath(CFX_RenderDevice* pDevice, - const std::vector<uint32_t>& charCodes, - const std::vector<float>& charPos, + pdfium::span<const uint32_t> char_codes, + pdfium::span<const float> char_pos, CPDF_Font* pFont, float font_size, const CFX_Matrix& mtText2User, @@ -42,12 +43,12 @@ const CFX_GraphStateData* pGraphState, FX_ARGB fill_argb, FX_ARGB stroke_argb, - CFX_PathData* pClippingPath, - int nFlag); + CFX_Path* pClippingPath, + const CFX_FillRenderOptions& fill_options); static bool DrawNormalText(CFX_RenderDevice* pDevice, - const std::vector<uint32_t>& charCodes, - const std::vector<float>& charPos, + pdfium::span<const uint32_t> char_codes, + pdfium::span<const float> char_pos, CPDF_Font* pFont, float font_size, const CFX_Matrix& mtText2Device,
diff --git a/core/fpdfapi/render/cpdf_type3cache.cpp b/core/fpdfapi/render/cpdf_type3cache.cpp index 41e630b..f009456 100644 --- a/core/fpdfapi/render/cpdf_type3cache.cpp +++ b/core/fpdfapi/render/cpdf_type3cache.cpp
@@ -1,4 +1,4 @@ -// Copyright 2016 PDFium Authors. All rights reserved. +// Copyright 2016 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -6,43 +6,23 @@ #include "core/fpdfapi/render/cpdf_type3cache.h" -#include <map> +#include <math.h> + #include <memory> #include <utility> #include "core/fpdfapi/font/cpdf_type3char.h" #include "core/fpdfapi/font/cpdf_type3font.h" -#include "core/fpdfapi/page/cpdf_docpagedata.h" -#include "core/fpdfapi/render/cpdf_docrenderdata.h" #include "core/fpdfapi/render/cpdf_type3glyphmap.h" #include "core/fxcrt/fx_coordinates.h" #include "core/fxcrt/fx_safe_types.h" #include "core/fxge/cfx_glyphbitmap.h" #include "core/fxge/dib/cfx_dibitmap.h" -#include "core/fxge/fx_dib.h" -#include "third_party/base/ptr_util.h" +#include "core/fxge/dib/fx_dib.h" namespace { -struct CPDF_UniqueKeyGen { - void Generate(int count, ...); - - int m_KeyLen; - char m_Key[128]; -}; - -void CPDF_UniqueKeyGen::Generate(int count, ...) { - va_list argList; - va_start(argList, count); - for (int i = 0; i < count; i++) { - int p = va_arg(argList, int); - (reinterpret_cast<uint32_t*>(m_Key))[i] = p; - } - va_end(argList); - m_KeyLen = count * sizeof(uint32_t); -} - -bool IsScanLine1bpp(uint8_t* pBuf, int width) { +bool IsScanLine1bpp(const uint8_t* pBuf, int width) { int size = width / 8; for (int i = 0; i < size; i++) { if (pBuf[i]) @@ -51,7 +31,7 @@ return (width % 8) && (pBuf[width / 8] & (0xff << (8 - width % 8))); } -bool IsScanLine8bpp(uint8_t* pBuf, int width) { +bool IsScanLine8bpp(const uint8_t* pBuf, int width) { for (int i = 0; i < width; i++) { if (pBuf[i] > 0x40) return true; @@ -59,26 +39,34 @@ return false; } -int DetectFirstLastScan(const RetainPtr<CFX_DIBitmap>& pBitmap, bool bFirst) { - int height = pBitmap->GetHeight(); - int pitch = pBitmap->GetPitch(); - int width = pBitmap->GetWidth(); - int bpp = pBitmap->GetBPP(); +bool IsScanLineBpp(int bpp, const uint8_t* pBuf, int width) { + if (bpp == 1) + return IsScanLine1bpp(pBuf, width); if (bpp > 8) width *= bpp / 8; - uint8_t* pBuf = pBitmap->GetBuffer(); - int line = bFirst ? 0 : height - 1; - int line_step = bFirst ? 1 : -1; - int line_end = bFirst ? height : -1; - while (line != line_end) { - if (bpp == 1) { - if (IsScanLine1bpp(pBuf + line * pitch, width)) - return line; - } else { - if (IsScanLine8bpp(pBuf + line * pitch, width)) - return line; - } - line += line_step; + return IsScanLine8bpp(pBuf, width); +} + +int DetectFirstScan(const RetainPtr<CFX_DIBitmap>& pBitmap) { + const int height = pBitmap->GetHeight(); + const int width = pBitmap->GetWidth(); + const int bpp = pBitmap->GetBPP(); + for (int line = 0; line < height; ++line) { + const uint8_t* pBuf = pBitmap->GetScanline(line).data(); + if (IsScanLineBpp(bpp, pBuf, width)) + return line; + } + return -1; +} + +int DetectLastScan(const RetainPtr<CFX_DIBitmap>& pBitmap) { + const int height = pBitmap->GetHeight(); + const int bpp = pBitmap->GetBPP(); + const int width = pBitmap->GetWidth(); + for (int line = height - 1; line >= 0; --line) { + const uint8_t* pBuf = pBitmap->GetScanline(line).data(); + if (IsScanLineBpp(bpp, pBuf, width)) + return line; } return -1; } @@ -90,18 +78,19 @@ CPDF_Type3Cache::~CPDF_Type3Cache() = default; const CFX_GlyphBitmap* CPDF_Type3Cache::LoadGlyph(uint32_t charcode, - const CFX_Matrix* pMatrix) { - CPDF_UniqueKeyGen keygen; - keygen.Generate( - 4, FXSYS_roundf(pMatrix->a * 10000), FXSYS_roundf(pMatrix->b * 10000), - FXSYS_roundf(pMatrix->c * 10000), FXSYS_roundf(pMatrix->d * 10000)); - ByteString FaceGlyphsKey(keygen.m_Key, keygen.m_KeyLen); + const CFX_Matrix& mtMatrix) { + SizeKey keygen = { + FXSYS_roundf(mtMatrix.a * 10000), + FXSYS_roundf(mtMatrix.b * 10000), + FXSYS_roundf(mtMatrix.c * 10000), + FXSYS_roundf(mtMatrix.d * 10000), + }; CPDF_Type3GlyphMap* pSizeCache; - auto it = m_SizeMap.find(FaceGlyphsKey); + auto it = m_SizeMap.find(keygen); if (it == m_SizeMap.end()) { - auto pNew = pdfium::MakeUnique<CPDF_Type3GlyphMap>(); + auto pNew = std::make_unique<CPDF_Type3GlyphMap>(); pSizeCache = pNew.get(); - m_SizeMap[FaceGlyphsKey] = std::move(pNew); + m_SizeMap[keygen] = std::move(pNew); } else { pSizeCache = it->second.get(); } @@ -110,7 +99,7 @@ return pExisting; std::unique_ptr<CFX_GlyphBitmap> pNewBitmap = - RenderGlyph(pSizeCache, charcode, pMatrix); + RenderGlyph(pSizeCache, charcode, mtMatrix); CFX_GlyphBitmap* pGlyphBitmap = pNewBitmap.get(); pSizeCache->SetBitmap(charcode, std::move(pNewBitmap)); return pGlyphBitmap; @@ -119,22 +108,25 @@ std::unique_ptr<CFX_GlyphBitmap> CPDF_Type3Cache::RenderGlyph( CPDF_Type3GlyphMap* pSize, uint32_t charcode, - const CFX_Matrix* pMatrix) { - const CPDF_Type3Char* pChar = m_pFont->LoadChar(charcode); - if (!pChar || !pChar->GetBitmap()) + const CFX_Matrix& mtMatrix) { + CPDF_Type3Char* pChar = m_pFont->LoadChar(charcode); + if (!pChar) return nullptr; - CFX_Matrix text_matrix(pMatrix->a, pMatrix->b, pMatrix->c, pMatrix->d, 0, 0); + RetainPtr<CFX_DIBitmap> pBitmap = pChar->GetBitmap(); + if (!pBitmap) + return nullptr; + + CFX_Matrix text_matrix(mtMatrix.a, mtMatrix.b, mtMatrix.c, mtMatrix.d, 0, 0); CFX_Matrix image_matrix = pChar->matrix() * text_matrix; - RetainPtr<CFX_DIBitmap> pBitmap = pChar->GetBitmap(); RetainPtr<CFX_DIBitmap> pResBitmap; int left = 0; int top = 0; if (fabs(image_matrix.b) < fabs(image_matrix.a) / 100 && fabs(image_matrix.c) < fabs(image_matrix.d) / 100) { - int top_line = DetectFirstLastScan(pBitmap, true); - int bottom_line = DetectFirstLastScan(pBitmap, false); + int top_line = DetectFirstScan(pBitmap); + int bottom_line = DetectLastScan(pBitmap); if (top_line == 0 && bottom_line == pBitmap->GetHeight() - 1) { float top_y = image_matrix.d + image_matrix.f; float bottom_y = image_matrix.f; @@ -162,7 +154,7 @@ if (!pResBitmap) return nullptr; - auto pGlyph = pdfium::MakeUnique<CFX_GlyphBitmap>(left, -top); + auto pGlyph = std::make_unique<CFX_GlyphBitmap>(left, -top); pGlyph->GetBitmap()->TakeOver(std::move(pResBitmap)); return pGlyph; }
diff --git a/core/fpdfapi/render/cpdf_type3cache.h b/core/fpdfapi/render/cpdf_type3cache.h index 4371a01..e154a72 100644 --- a/core/fpdfapi/render/cpdf_type3cache.h +++ b/core/fpdfapi/render/cpdf_type3cache.h
@@ -1,4 +1,4 @@ -// Copyright 2016 PDFium Authors. All rights reserved. +// Copyright 2016 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -7,11 +7,13 @@ #ifndef CORE_FPDFAPI_RENDER_CPDF_TYPE3CACHE_H_ #define CORE_FPDFAPI_RENDER_CPDF_TYPE3CACHE_H_ +#include <stdint.h> + #include <map> #include <memory> +#include <tuple> -#include "core/fxcrt/fx_string.h" -#include "core/fxcrt/fx_system.h" +#include "core/fxcrt/bytestring.h" #include "core/fxcrt/observed_ptr.h" #include "core/fxcrt/retain_ptr.h" @@ -22,22 +24,23 @@ class CPDF_Type3Cache final : public Retainable, public Observable { public: - template <typename T, typename... Args> - friend RetainPtr<T> pdfium::MakeRetain(Args&&... args); + CONSTRUCT_VIA_MAKE_RETAIN; const CFX_GlyphBitmap* LoadGlyph(uint32_t charcode, - const CFX_Matrix* pMatrix); + const CFX_Matrix& mtMatrix); private: + using SizeKey = std::tuple<int, int, int, int>; + explicit CPDF_Type3Cache(CPDF_Type3Font* pFont); ~CPDF_Type3Cache() override; std::unique_ptr<CFX_GlyphBitmap> RenderGlyph(CPDF_Type3GlyphMap* pSize, uint32_t charcode, - const CFX_Matrix* pMatrix); + const CFX_Matrix& mtMatrix); RetainPtr<CPDF_Type3Font> const m_pFont; - std::map<ByteString, std::unique_ptr<CPDF_Type3GlyphMap>> m_SizeMap; + std::map<SizeKey, std::unique_ptr<CPDF_Type3GlyphMap>> m_SizeMap; }; #endif // CORE_FPDFAPI_RENDER_CPDF_TYPE3CACHE_H_
diff --git a/core/fpdfapi/render/cpdf_type3glyphmap.cpp b/core/fpdfapi/render/cpdf_type3glyphmap.cpp index b144991..10b2b4a 100644 --- a/core/fpdfapi/render/cpdf_type3glyphmap.cpp +++ b/core/fpdfapi/render/cpdf_type3glyphmap.cpp
@@ -1,4 +1,4 @@ -// Copyright 2016 PDFium Authors. All rights reserved. +// Copyright 2016 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -6,10 +6,12 @@ #include "core/fpdfapi/render/cpdf_type3glyphmap.h" +#include <math.h> + #include <algorithm> -#include <map> #include <utility> +#include "core/fxcrt/fx_system.h" #include "core/fxge/cfx_glyphbitmap.h" #include "core/fxge/fx_font.h" @@ -39,7 +41,7 @@ CPDF_Type3GlyphMap::CPDF_Type3GlyphMap() {} -CPDF_Type3GlyphMap::~CPDF_Type3GlyphMap() {} +CPDF_Type3GlyphMap::~CPDF_Type3GlyphMap() = default; std::pair<int, int> CPDF_Type3GlyphMap::AdjustBlue(float top, float bottom) { return std::make_pair(AdjustBlueHelper(top, &m_TopBlue),
diff --git a/core/fpdfapi/render/cpdf_type3glyphmap.h b/core/fpdfapi/render/cpdf_type3glyphmap.h index fced0ee..4965732 100644 --- a/core/fpdfapi/render/cpdf_type3glyphmap.h +++ b/core/fpdfapi/render/cpdf_type3glyphmap.h
@@ -1,4 +1,4 @@ -// Copyright 2016 PDFium Authors. All rights reserved. +// Copyright 2016 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -7,13 +7,13 @@ #ifndef CORE_FPDFAPI_RENDER_CPDF_TYPE3GLYPHMAP_H_ #define CORE_FPDFAPI_RENDER_CPDF_TYPE3GLYPHMAP_H_ +#include <stdint.h> + #include <map> #include <memory> #include <utility> #include <vector> -#include "core/fxcrt/fx_system.h" - class CFX_GlyphBitmap; class CPDF_Type3GlyphMap {
diff --git a/core/fpdfapi/render/cpdf_windowsrenderdevice.cpp b/core/fpdfapi/render/cpdf_windowsrenderdevice.cpp index 8e1f212..78410dd 100644 --- a/core/fpdfapi/render/cpdf_windowsrenderdevice.cpp +++ b/core/fpdfapi/render/cpdf_windowsrenderdevice.cpp
@@ -1,4 +1,4 @@ -// Copyright 2019 PDFium Authors. All rights reserved. +// Copyright 2019 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -6,6 +6,8 @@ #include "core/fpdfapi/render/cpdf_windowsrenderdevice.h" +#include <sstream> + #include "core/fxcodec/basic/basicmodule.h" #include "core/fxcodec/fax/faxmodule.h" #include "core/fxcodec/flate/flatemodule.h" @@ -20,7 +22,9 @@ } // namespace -CPDF_WindowsRenderDevice::CPDF_WindowsRenderDevice(HDC hDC) - : CFX_WindowsRenderDevice(hDC, &kEncoderIface) {} +CPDF_WindowsRenderDevice::CPDF_WindowsRenderDevice( + HDC hDC, + CFX_PSFontTracker* ps_font_tracker) + : CFX_WindowsRenderDevice(hDC, ps_font_tracker, &kEncoderIface) {} CPDF_WindowsRenderDevice::~CPDF_WindowsRenderDevice() = default;
diff --git a/core/fpdfapi/render/cpdf_windowsrenderdevice.h b/core/fpdfapi/render/cpdf_windowsrenderdevice.h index 51d150e..c83c588 100644 --- a/core/fpdfapi/render/cpdf_windowsrenderdevice.h +++ b/core/fpdfapi/render/cpdf_windowsrenderdevice.h
@@ -1,4 +1,4 @@ -// Copyright 2019 PDFium Authors. All rights reserved. +// Copyright 2019 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -9,9 +9,11 @@ #include "core/fxge/cfx_windowsrenderdevice.h" +class CFX_PSFontTracker; + class CPDF_WindowsRenderDevice final : public CFX_WindowsRenderDevice { public: - explicit CPDF_WindowsRenderDevice(HDC hDC); + CPDF_WindowsRenderDevice(HDC hDC, CFX_PSFontTracker* ps_font_tracker); ~CPDF_WindowsRenderDevice() override; };
diff --git a/core/fpdfapi/render/fpdf_progressive_render_embeddertest.cpp b/core/fpdfapi/render/fpdf_progressive_render_embeddertest.cpp index 271a251..a51e16e 100644 --- a/core/fpdfapi/render/fpdf_progressive_render_embeddertest.cpp +++ b/core/fpdfapi/render/fpdf_progressive_render_embeddertest.cpp
@@ -1,28 +1,81 @@ -// Copyright 2019 PDFium Authors. All rights reserved. +// Copyright 2019 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include <stdint.h> + #include <utility> #include "build/build_config.h" -#include "core/fxcrt/fx_system.h" +#include "core/fxge/cfx_defaultrenderdevice.h" +#include "core/fxge/dib/fx_dib.h" #include "public/fpdf_progressive.h" #include "testing/embedder_test.h" +#include "testing/embedder_test_constants.h" #include "testing/gtest/include/gtest/gtest.h" +#include "third_party/base/check.h" + +namespace { + +constexpr FX_ARGB kBlack = 0xFF000000; +constexpr FX_ARGB kBlue = 0xFF0000FF; +constexpr FX_ARGB kGreen = 0xFF00FF00; +constexpr FX_ARGB kRed = 0xFFFF0000; +constexpr FX_ARGB kWhite = 0xFFFFFFFF; + +const char* AnnotationStampWithApBaseContentChecksum() { +#if BUILDFLAG(IS_APPLE) + if (!CFX_DefaultRenderDevice::SkiaIsDefaultRenderer()) + return "243f3d6267d9db09198fed9f8c4957fd"; +#endif + return "e31414933c9ff3950773981e5bf61678"; +} + +} // namespace class FPDFProgressiveRenderEmbedderTest : public EmbedderTest { public: + class FakePause : public IFSDK_PAUSE { + public: + explicit FakePause(bool should_pause) : should_pause_(should_pause) { + IFSDK_PAUSE::version = 1; + IFSDK_PAUSE::user = nullptr; + IFSDK_PAUSE::NeedToPauseNow = Pause_NeedToPauseNow; + } + ~FakePause() = default; + static FPDF_BOOL Pause_NeedToPauseNow(IFSDK_PAUSE* param) { + return static_cast<FakePause*>(param)->should_pause_; + } + + private: + const bool should_pause_; + }; + // StartRenderPageWithFlags() with no flags. // The call returns true if the rendering is complete. bool StartRenderPage(FPDF_PAGE page, IFSDK_PAUSE* pause); - // Start rendering of |page| into a bitmap with the ability to pause the + // Start rendering of |page| into a bitmap with the ability to |pause| the // rendering with the specified rendering |flags|. // The call returns true if the rendering is complete. // // See public/fpdfview.h for a list of page rendering flags. bool StartRenderPageWithFlags(FPDF_PAGE page, IFSDK_PAUSE* pause, int flags); + // Start rendering of |page| into a bitmap with the ability to pause the + // rendering with the specified rendering |flags| and the specified + // |color_scheme|. This also takes in the |background_color| for the bitmap. + // The call returns true if the rendering is complete. + // + // See public/fpdfview.h for the list of page rendering flags and + // the list of colors in the scheme. + bool StartRenderPageWithColorSchemeAndBackground( + FPDF_PAGE page, + IFSDK_PAUSE* pause, + int flags, + const FPDF_COLORSCHEME* color_scheme, + uint32_t background_color); + // Continue rendering of |page| into the bitmap created in // StartRenderPageWithFlags(). // The call returns true if the rendering is complete. @@ -40,6 +93,33 @@ ScopedFPDFBitmap FinishRenderPageWithForms(FPDF_PAGE page, FPDF_FORMHANDLE handle); + // Convert the |page| into a bitmap with a |background_color|, using the + // color scheme render API with the specific |flags| and |color_scheme|. + // The form handle associated with |page| should be passed in via |handle|. + // If |handle| is nullptr, then forms on the page will not be rendered. + // This returns the bitmap generated by the progressive render calls. + // + // See public/fpdfview.h for a list of page rendering flags and + // the color scheme that can be applied for rendering. + ScopedFPDFBitmap RenderPageWithForcedColorScheme( + FPDF_PAGE page, + FPDF_FORMHANDLE handle, + int flags, + const FPDF_COLORSCHEME* color_scheme, + FX_ARGB background_color); + + protected: + // Utility method to render the |page_num| of the currently loaded Pdf + // using RenderPageWithForcedColorScheme() passing in the render options + // and expected values for bitmap verification. + void VerifyRenderingWithColorScheme(int page_num, + int flags, + const FPDF_COLORSCHEME* color_scheme, + FX_ARGB background_color, + int bitmap_width, + int bitmap_height, + const char* md5); + private: // Keeps the bitmap used for progressive rendering alive until // FPDF_RenderPage_Close() is called after which the bitmap is returned @@ -72,9 +152,31 @@ return rv != FPDF_RENDER_TOBECONTINUED; } +bool FPDFProgressiveRenderEmbedderTest:: + StartRenderPageWithColorSchemeAndBackground( + FPDF_PAGE page, + IFSDK_PAUSE* pause, + int flags, + const FPDF_COLORSCHEME* color_scheme, + uint32_t background_color) { + int width = static_cast<int>(FPDF_GetPageWidth(page)); + int height = static_cast<int>(FPDF_GetPageHeight(page)); + progressive_render_flags_ = flags; + int alpha = FPDFPage_HasTransparency(page) ? 1 : 0; + progressive_render_bitmap_ = + ScopedFPDFBitmap(FPDFBitmap_Create(width, height, alpha)); + DCHECK(progressive_render_bitmap_); + FPDFBitmap_FillRect(progressive_render_bitmap_.get(), 0, 0, width, height, + background_color); + int rv = FPDF_RenderPageBitmapWithColorScheme_Start( + progressive_render_bitmap_.get(), page, 0, 0, width, height, 0, + progressive_render_flags_, color_scheme, pause); + return rv != FPDF_RENDER_TOBECONTINUED; +} + bool FPDFProgressiveRenderEmbedderTest::ContinueRenderPage(FPDF_PAGE page, IFSDK_PAUSE* pause) { - ASSERT(progressive_render_bitmap_); + DCHECK(progressive_render_bitmap_); int rv = FPDF_RenderPage_Continue(page, pause); return rv != FPDF_RENDER_TOBECONTINUED; @@ -88,7 +190,7 @@ ScopedFPDFBitmap FPDFProgressiveRenderEmbedderTest::FinishRenderPageWithForms( FPDF_PAGE page, FPDF_FORMHANDLE handle) { - ASSERT(progressive_render_bitmap_); + DCHECK(progressive_render_bitmap_); int width = static_cast<int>(FPDF_GetPageWidth(page)); int height = static_cast<int>(FPDF_GetPageHeight(page)); @@ -98,68 +200,43 @@ return std::move(progressive_render_bitmap_); } -class FakePause : public IFSDK_PAUSE { - public: - explicit FakePause(bool should_pause) : should_pause_(should_pause) { - IFSDK_PAUSE::version = 1; - IFSDK_PAUSE::user = nullptr; - IFSDK_PAUSE::NeedToPauseNow = Pause_NeedToPauseNow; +ScopedFPDFBitmap +FPDFProgressiveRenderEmbedderTest::RenderPageWithForcedColorScheme( + FPDF_PAGE page, + FPDF_FORMHANDLE handle, + int flags, + const FPDF_COLORSCHEME* color_scheme, + FX_ARGB background_color) { + FakePause pause(true); + bool render_done = StartRenderPageWithColorSchemeAndBackground( + page, &pause, flags, color_scheme, background_color) == + FPDF_RENDER_TOBECONTINUED; + EXPECT_FALSE(render_done); + + while (!render_done) { + render_done = ContinueRenderPage(page, &pause); } - ~FakePause() = default; + return FinishRenderPageWithForms(page, form_handle()); +} - static FPDF_BOOL Pause_NeedToPauseNow(IFSDK_PAUSE* param) { - return static_cast<FakePause*>(param)->should_pause_; - } - - private: - const bool should_pause_ = false; -}; - -// TODO(crbug.com/pdfium/11): Fix this test and enable. -#if defined(_SKIA_SUPPORT_) || defined(_SKIA_SUPPORT_PATHS_) -#define MAYBE_RenderWithoutPause DISABLED_RenderWithoutPause -#else -#define MAYBE_RenderWithoutPause RenderWithoutPause -#endif -TEST_F(FPDFProgressiveRenderEmbedderTest, MAYBE_RenderWithoutPause) { -#if defined(OS_WIN) - static constexpr char kMd5BaseContent[] = "649d6792ea50faf98c013c2d81710595"; -#elif defined(OS_MACOSX) - static constexpr char kMd5BaseContent[] = "5f933aac2a74434be1b4d0bdb5334f0b"; -#else - static constexpr char kMd5BaseContent[] = "a24edc7740f1d6f76899652dcf825dea"; -#endif - +TEST_F(FPDFProgressiveRenderEmbedderTest, RenderWithoutPause) { // Test rendering of page content using progressive render APIs // without pausing the rendering. - EXPECT_TRUE(OpenDocument("annotation_stamp_with_ap.pdf")); + ASSERT_TRUE(OpenDocument("annotation_stamp_with_ap.pdf")); FPDF_PAGE page = LoadPage(0); ASSERT_TRUE(page); FakePause pause(false); EXPECT_TRUE(StartRenderPage(page, &pause)); ScopedFPDFBitmap bitmap = FinishRenderPage(page); - CompareBitmap(bitmap.get(), 595, 842, kMd5BaseContent); + CompareBitmap(bitmap.get(), 595, 842, + AnnotationStampWithApBaseContentChecksum()); UnloadPage(page); } -// TODO(crbug.com/pdfium/11): Fix this test and enable. -#if defined(_SKIA_SUPPORT_) || defined(_SKIA_SUPPORT_PATHS_) -#define MAYBE_RenderWithPause DISABLED_RenderWithPause -#else -#define MAYBE_RenderWithPause RenderWithPause -#endif -TEST_F(FPDFProgressiveRenderEmbedderTest, MAYBE_RenderWithPause) { -#if defined(OS_WIN) - static constexpr char kMd5BaseContent[] = "649d6792ea50faf98c013c2d81710595"; -#elif defined(OS_MACOSX) - static constexpr char kMd5BaseContent[] = "5f933aac2a74434be1b4d0bdb5334f0b"; -#else - static constexpr char kMd5BaseContent[] = "a24edc7740f1d6f76899652dcf825dea"; -#endif - +TEST_F(FPDFProgressiveRenderEmbedderTest, RenderWithPause) { // Test rendering of page content using progressive render APIs // with pause in rendering. - EXPECT_TRUE(OpenDocument("annotation_stamp_with_ap.pdf")); + ASSERT_TRUE(OpenDocument("annotation_stamp_with_ap.pdf")); FPDF_PAGE page = LoadPage(0); ASSERT_TRUE(page); FakePause pause(true); @@ -170,31 +247,15 @@ render_done = ContinueRenderPage(page, &pause); } ScopedFPDFBitmap bitmap = FinishRenderPage(page); - CompareBitmap(bitmap.get(), 595, 842, kMd5BaseContent); + CompareBitmap(bitmap.get(), 595, 842, + AnnotationStampWithApBaseContentChecksum()); UnloadPage(page); } -// TODO(crbug.com/pdfium/11): Fix this test and enable. -#if defined(_SKIA_SUPPORT_) || defined(_SKIA_SUPPORT_PATHS_) -#define MAYBE_RenderAnnotWithPause DISABLED_RenderAnnotWithPause -#else -#define MAYBE_RenderAnnotWithPause RenderAnnotWithPause -#endif -TEST_F(FPDFProgressiveRenderEmbedderTest, MAYBE_RenderAnnotWithPause) { -#if defined(OS_WIN) - static constexpr char kMd5ContentWithAnnot[] = - "6aa001a77ec05d0f1b0d1d22e28744d4"; -#elif defined(OS_MACOSX) - static constexpr char kMd5ContentWithAnnot[] = - "c35408717759562d1f8bf33d317483d2"; -#else - static constexpr char kMd5ContentWithAnnot[] = - "b42cef463483e668eaf4055a65e4f1f5"; -#endif - +TEST_F(FPDFProgressiveRenderEmbedderTest, RenderAnnotWithPause) { // Test rendering of the page with annotations using progressive render APIs // with pause in rendering. - EXPECT_TRUE(OpenDocument("annotation_stamp_with_ap.pdf")); + ASSERT_TRUE(OpenDocument("annotation_stamp_with_ap.pdf")); FPDF_PAGE page = LoadPage(0); ASSERT_TRUE(page); FakePause pause(true); @@ -205,31 +266,15 @@ render_done = ContinueRenderPage(page, &pause); } ScopedFPDFBitmap bitmap = FinishRenderPage(page); - CompareBitmap(bitmap.get(), 595, 842, kMd5ContentWithAnnot); + CompareBitmap(bitmap.get(), 595, 842, + pdfium::AnnotationStampWithApChecksum()); UnloadPage(page); } -// TODO(crbug.com/pdfium/11): Fix this test and enable. -#if defined(_SKIA_SUPPORT_) || defined(_SKIA_SUPPORT_PATHS_) -#define MAYBE_RenderFormsWithPause DISABLED_RenderFormsWithPause -#else -#define MAYBE_RenderFormsWithPause RenderFormsWithPause -#endif -TEST_F(FPDFProgressiveRenderEmbedderTest, MAYBE_RenderFormsWithPause) { -#if defined(OS_WIN) - static constexpr char kMd5ContentWithForms[] = - "d3204faa62b607f0bd3893c9c22cabcb"; -#elif defined(OS_MACOSX) - static constexpr char kMd5ContentWithForms[] = - "5f11dbe575fe197a37c3fb422559f8ff"; -#else - static constexpr char kMd5ContentWithForms[] = - "b890950d4b9bc163b1a96797f3004b53"; -#endif - +TEST_F(FPDFProgressiveRenderEmbedderTest, RenderFormsWithPause) { // Test rendering of the page with forms using progressive render APIs // with pause in rendering. - EXPECT_TRUE(OpenDocument("text_form.pdf")); + ASSERT_TRUE(OpenDocument("text_form.pdf")); FPDF_PAGE page = LoadPage(0); ASSERT_TRUE(page); FakePause pause(true); @@ -239,7 +284,184 @@ while (!render_done) { render_done = ContinueRenderPage(page, &pause); } - ScopedFPDFBitmap bitmap = FinishRenderPageWithForms(page, form_handle_); - CompareBitmap(bitmap.get(), 300, 300, kMd5ContentWithForms); + ScopedFPDFBitmap bitmap = FinishRenderPageWithForms(page, form_handle()); + CompareBitmap(bitmap.get(), 300, 300, pdfium::TextFormChecksum()); UnloadPage(page); } + +void FPDFProgressiveRenderEmbedderTest::VerifyRenderingWithColorScheme( + int page_num, + int flags, + const FPDF_COLORSCHEME* color_scheme, + FX_ARGB background_color, + int bitmap_width, + int bitmap_height, + const char* md5) { + ASSERT_TRUE(document()); + + FPDF_PAGE page = LoadPage(page_num); + ASSERT_TRUE(page); + + ScopedFPDFBitmap bitmap = RenderPageWithForcedColorScheme( + page, form_handle(), flags, color_scheme, background_color); + ASSERT_TRUE(bitmap); + CompareBitmap(bitmap.get(), bitmap_width, bitmap_height, md5); + UnloadPage(page); +} + +TEST_F(FPDFProgressiveRenderEmbedderTest, RenderTextWithColorScheme) { + // Test rendering of text with forced color scheme on. + const char* content_with_text_checksum = []() { + if (CFX_DefaultRenderDevice::SkiaIsDefaultRenderer()) + return "5ece6059efdc2ecb2894fa3cf329dc94"; +#if BUILDFLAG(IS_APPLE) + return "ee4ec12f54ce8d117a73bd9b85a8954d"; +#else + return "704db63ed2bf77254ecaa8035b85f21a"; +#endif // BUILDFLAG(IS_APPLE) + }(); + + ASSERT_TRUE(OpenDocument("hello_world.pdf")); + + FPDF_COLORSCHEME color_scheme{kBlack, kWhite, kWhite, kWhite}; + VerifyRenderingWithColorScheme(/*page_num=*/0, /*flags=*/0, &color_scheme, + kBlack, 200, 200, content_with_text_checksum); +} + +TEST_F(FPDFProgressiveRenderEmbedderTest, RenderPathWithColorScheme) { + // Test rendering of paths with forced color scheme on. + const char* rectangles_checksum = []() { + if (CFX_DefaultRenderDevice::SkiaIsDefaultRenderer()) + return "4b0f850a94698d07b6cd2814d1b4ccb7"; + return "249f59b0d066c4f6bd89782a80822219"; + }(); + + ASSERT_TRUE(OpenDocument("rectangles.pdf")); + + FPDF_COLORSCHEME color_scheme{kWhite, kRed, kBlue, kBlue}; + VerifyRenderingWithColorScheme(/*page_num=*/0, /*flags=*/0, &color_scheme, + kBlack, 200, 300, rectangles_checksum); +} + +TEST_F(FPDFProgressiveRenderEmbedderTest, + RenderPathWithColorSchemeAndConvertFillToStroke) { + // Test rendering of paths with forced color scheme on and conversion from + // fill to stroke enabled. The fill paths should be rendered as stroke. + const char* rectangles_checksum = []() { + if (CFX_DefaultRenderDevice::SkiaIsDefaultRenderer()) + return "c1cbbd2ce6921f608a3c55140592419b"; + return "0ebcc11e617635eca1fa9ce475383a80"; + }(); + + ASSERT_TRUE(OpenDocument("rectangles.pdf")); + + FPDF_COLORSCHEME color_scheme{kWhite, kRed, kBlue, kBlue}; + VerifyRenderingWithColorScheme(/*page_num=*/0, FPDF_CONVERT_FILL_TO_STROKE, + &color_scheme, kBlack, 200, 300, + rectangles_checksum); +} + +TEST_F(FPDFProgressiveRenderEmbedderTest, RenderHighlightWithColorScheme) { + // Test rendering of highlight with forced color scheme on. + // + // Note: The fill color rendered for highlight is different from the normal + // path since highlights have Multiply blend mode, while the other path has + // Normal blend mode. + const char* content_with_highlight_fill_checksum = []() { + if (CFX_DefaultRenderDevice::SkiaIsDefaultRenderer()) + return "9b6273fdbc9db780c49f7540756209f8"; +#if BUILDFLAG(IS_APPLE) + return "a820afec9b99d3d3f2e9e9382bbad7c1"; +#else + return "a08a0639f89446f66f3689ee8e08b9fe"; +#endif // BUILDFLAG(IS_APPLE) + }(); + + ASSERT_TRUE(OpenDocument("annotation_highlight_square_with_ap.pdf")); + + FPDF_COLORSCHEME color_scheme{kRed, kGreen, kWhite, kWhite}; + VerifyRenderingWithColorScheme(/*page_num=*/0, FPDF_ANNOT, &color_scheme, + kBlue, 612, 792, + content_with_highlight_fill_checksum); +} + +TEST_F(FPDFProgressiveRenderEmbedderTest, + RenderHighlightWithColorSchemeAndConvertFillToStroke) { + // Test rendering of highlight with forced color and converting fill to + // stroke. The highlight should be rendered as a stroke of the rect. + // + // Note: The stroke color rendered for highlight is different from the normal + // path since highlights have Multiply blend mode, while the other path has + // Normal blend mode. + + const char* md5_content_with_highlight = []() { + if (CFX_DefaultRenderDevice::SkiaIsDefaultRenderer()) + return "772246195d18f75d40a22bee913c098f"; +#if BUILDFLAG(IS_APPLE) + return "8837bea0b3520164b1784e513c882a2d"; +#else + return "3dd8c02f5c06bac85e0d2c8bf37d1dc4"; +#endif // BUILDFLAG(IS_APPLE) + }(); + + ASSERT_TRUE(OpenDocument("annotation_highlight_square_with_ap.pdf")); + + FPDF_COLORSCHEME color_scheme{kRed, kGreen, kWhite, kWhite}; + VerifyRenderingWithColorScheme( + /*page_num=*/0, FPDF_ANNOT | FPDF_CONVERT_FILL_TO_STROKE, &color_scheme, + kBlue, 612, 792, md5_content_with_highlight); +} + +TEST_F(FPDFProgressiveRenderEmbedderTest, RenderInkWithColorScheme) { + // Test rendering of multiple ink with forced color scheme on. + const char* content_with_ink_checksum = []() { + if (CFX_DefaultRenderDevice::SkiaIsDefaultRenderer()) + return "ebc57721e4c8da34156e09b9b2e62fb0"; + return "797bce7dc6c50ee86b095405df9fe5aa"; + }(); + + ASSERT_TRUE(OpenDocument("annotation_ink_multiple.pdf")); + + FPDF_COLORSCHEME color_scheme{kBlack, kGreen, kRed, kRed}; + VerifyRenderingWithColorScheme(/*page_num=*/0, FPDF_ANNOT, &color_scheme, + kBlack, 612, 792, content_with_ink_checksum); +} + +TEST_F(FPDFProgressiveRenderEmbedderTest, RenderStampWithColorScheme) { + // Test rendering of static annotation with forced color scheme on. + const char* content_with_stamp_checksum = []() { + if (CFX_DefaultRenderDevice::SkiaIsDefaultRenderer()) + return "a791fdb4f595bb6c4187cc2aeed5e9e8"; +#if BUILDFLAG(IS_APPLE) + return "8170c539e95f22f14eb8f266a5f1bbed"; +#else + return "d1fd087e59d4dcebf47b56570bdb8c22"; +#endif + }(); + + ASSERT_TRUE(OpenDocument("annotation_stamp_with_ap.pdf")); + + FPDF_COLORSCHEME color_scheme{kBlue, kGreen, kRed, kRed}; + VerifyRenderingWithColorScheme(/*page_num=*/0, FPDF_ANNOT, &color_scheme, + kWhite, 595, 842, content_with_stamp_checksum); +} + +TEST_F(FPDFProgressiveRenderEmbedderTest, RenderFormWithColorScheme) { + // Test rendering of form does not change with forced color scheme on. + const char* content_with_form_checksum = []() { + if (CFX_DefaultRenderDevice::SkiaIsDefaultRenderer()) + return "9f75d98afc6d6313bd87e6562ea6df15"; + return "080f7a4381606659301440e1b14dca35"; + }(); + + ASSERT_TRUE(OpenDocument("annotiter.pdf")); + + FPDF_COLORSCHEME color_scheme{kGreen, kGreen, kRed, kRed}; + VerifyRenderingWithColorScheme(/*page_num=*/0, FPDF_ANNOT, &color_scheme, + kWhite, 612, 792, content_with_form_checksum); + + // Verify that the MD5 hash matches when rendered without |color_scheme|. + VerifyRenderingWithColorScheme(/*page_num=*/0, FPDF_ANNOT, + /*color_scheme=*/nullptr, kWhite, 612, 792, + content_with_form_checksum); +}
diff --git a/core/fpdfapi/render/fpdf_render_pattern_embeddertest.cpp b/core/fpdfapi/render/fpdf_render_pattern_embeddertest.cpp index 6de721c..f3b6cae 100644 --- a/core/fpdfapi/render/fpdf_render_pattern_embeddertest.cpp +++ b/core/fpdfapi/render/fpdf_render_pattern_embeddertest.cpp
@@ -1,21 +1,20 @@ -// Copyright 2015 PDFium Authors. All rights reserved. +// Copyright 2015 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include <memory> - #include "public/cpp/fpdf_scopers.h" #include "testing/embedder_test.h" +#include "testing/embedder_test_constants.h" #include "testing/gtest/include/gtest/gtest.h" class FPDFRenderPatternEmbedderTest : public EmbedderTest {}; TEST_F(FPDFRenderPatternEmbedderTest, LoadError_547706) { // Test shading where object is a dictionary instead of a stream. - EXPECT_TRUE(OpenDocument("bug_547706.pdf")); + ASSERT_TRUE(OpenDocument("bug_547706.pdf")); FPDF_PAGE page = LoadPage(0); ASSERT_TRUE(page); ScopedFPDFBitmap bitmap = RenderLoadedPage(page); - CompareBitmap(bitmap.get(), 612, 792, "1940568c9ba33bac5d0b1ee9558c76b3"); + CompareBitmap(bitmap.get(), 612, 792, pdfium::kBlankPage612By792Checksum); UnloadPage(page); }
diff --git a/core/fpdfdoc/Android.bp b/core/fpdfdoc/Android.bp index 6931dc5..00321a4 100644 --- a/core/fpdfdoc/Android.bp +++ b/core/fpdfdoc/Android.bp
@@ -13,11 +13,8 @@ visibility: ["//external/pdfium:__subpackages__"], - header_libs: [ - "libpdfium-constants", - ], - static_libs: [ + "libpdfium-constants", "libpdfium-font", "libpdfium-page", "libpdfium-parser",
diff --git a/core/fpdfdoc/BUILD.gn b/core/fpdfdoc/BUILD.gn index f25ace9..2e7a150 100644 --- a/core/fpdfdoc/BUILD.gn +++ b/core/fpdfdoc/BUILD.gn
@@ -1,4 +1,4 @@ -# Copyright 2018 The PDFium Authors. All rights reserved. +# Copyright 2018 The PDFium Authors # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. @@ -7,10 +7,6 @@ source_set("fpdfdoc") { sources = [ - "cba_fontmap.cpp", - "cba_fontmap.h", - "cline.cpp", - "cline.h", "cpdf_aaction.cpp", "cpdf_aaction.h", "cpdf_action.cpp", @@ -21,6 +17,8 @@ "cpdf_annotlist.h", "cpdf_apsettings.cpp", "cpdf_apsettings.h", + "cpdf_bafontmap.cpp", + "cpdf_bafontmap.h", "cpdf_bookmark.cpp", "cpdf_bookmark.h", "cpdf_bookmarktree.cpp", @@ -37,6 +35,8 @@ "cpdf_formcontrol.h", "cpdf_formfield.cpp", "cpdf_formfield.h", + "cpdf_generateap.cpp", + "cpdf_generateap.h", "cpdf_icon.cpp", "cpdf_icon.h", "cpdf_iconfit.cpp", @@ -59,29 +59,28 @@ "cpdf_structelement.h", "cpdf_structtree.cpp", "cpdf_structtree.h", - "cpdf_variabletext.cpp", - "cpdf_variabletext.h", "cpdf_viewerpreferences.cpp", "cpdf_viewerpreferences.h", "cpvt_floatrect.h", "cpvt_fontmap.cpp", "cpvt_fontmap.h", - "cpvt_generateap.cpp", - "cpvt_generateap.h", "cpvt_line.h", "cpvt_lineinfo.h", + "cpvt_section.cpp", + "cpvt_section.h", + "cpvt_variabletext.cpp", + "cpvt_variabletext.h", "cpvt_word.h", "cpvt_wordinfo.cpp", "cpvt_wordinfo.h", "cpvt_wordplace.h", "cpvt_wordrange.h", - "csection.cpp", - "csection.h", - "ctypeset.cpp", - "ctypeset.h", "ipvt_fontmap.h", ] - configs += [ "../../:pdfium_core_config" ] + configs += [ + "../../:pdfium_strict_config", + "../../:pdfium_noshorten_config", + ] deps = [ "../../constants", "../fpdfapi/font", @@ -96,7 +95,9 @@ pdfium_unittest_source_set("unittests") { sources = [ + "cpdf_action_unittest.cpp", "cpdf_annot_unittest.cpp", + "cpdf_bafontmap_unittest.cpp", "cpdf_defaultappearance_unittest.cpp", "cpdf_dest_unittest.cpp", "cpdf_filespec_unittest.cpp", @@ -106,7 +107,13 @@ ] deps = [ ":fpdfdoc", + "../../constants", + "../fpdfapi/font", + "../fpdfapi/page", + "../fpdfapi/page:unit_test_support", "../fpdfapi/parser", + "../fpdfapi/parser:unit_test_support", + "../fpdfapi/render", ] pdfium_root_dir = "../../" }
diff --git a/core/fpdfdoc/cba_fontmap.cpp b/core/fpdfdoc/cba_fontmap.cpp deleted file mode 100644 index c71c724..0000000 --- a/core/fpdfdoc/cba_fontmap.cpp +++ /dev/null
@@ -1,493 +0,0 @@ -// Copyright 2014 PDFium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com - -#include "core/fpdfdoc/cba_fontmap.h" - -#include <memory> -#include <utility> - -#include "constants/annotation_common.h" -#include "core/fpdfapi/font/cpdf_font.h" -#include "core/fpdfapi/font/cpdf_fontencoding.h" -#include "core/fpdfapi/page/cpdf_docpagedata.h" -#include "core/fpdfapi/page/cpdf_page.h" -#include "core/fpdfapi/parser/cpdf_dictionary.h" -#include "core/fpdfapi/parser/cpdf_document.h" -#include "core/fpdfapi/parser/cpdf_parser.h" -#include "core/fpdfapi/parser/cpdf_reference.h" -#include "core/fpdfapi/parser/cpdf_stream.h" -#include "core/fpdfapi/parser/fpdf_parser_utility.h" -#include "core/fpdfdoc/cpdf_defaultappearance.h" -#include "core/fpdfdoc/cpdf_formfield.h" -#include "core/fpdfdoc/ipvt_fontmap.h" -#include "core/fxcrt/fx_codepage.h" -#include "core/fxge/cfx_fontmapper.h" -#include "core/fxge/cfx_fontmgr.h" -#include "core/fxge/cfx_gemodule.h" -#include "core/fxge/cfx_substfont.h" -#include "third_party/base/ptr_util.h" -#include "third_party/base/stl_util.h" - -namespace { - -bool FindNativeTrueTypeFont(ByteString sFontFaceName) { - CFX_FontMgr* pFontMgr = CFX_GEModule::Get()->GetFontMgr(); - if (!pFontMgr) - return false; - - CFX_FontMapper* pFontMapper = pFontMgr->GetBuiltinMapper(); - pFontMapper->LoadInstalledFonts(); - - for (const auto& font : pFontMapper->m_InstalledTTFonts) { - if (font.Compare(sFontFaceName.AsStringView())) - return true; - } - for (const auto& fontPair : pFontMapper->m_LocalizedTTFonts) { - if (fontPair.first.Compare(sFontFaceName.AsStringView())) - return true; - } - return false; -} - -RetainPtr<CPDF_Font> AddNativeTrueTypeFontToPDF(CPDF_Document* pDoc, - ByteString sFontFaceName, - uint8_t nCharset) { - if (!pDoc) - return nullptr; - - auto pFXFont = pdfium::MakeUnique<CFX_Font>(); - pFXFont->LoadSubst(sFontFaceName, true, 0, 0, 0, - FX_GetCodePageFromCharset(nCharset), false); - - auto* pDocPageData = CPDF_DocPageData::FromDocument(pDoc); - return pDocPageData->AddFont(std::move(pFXFont), nCharset); -} - -} // namespace - -CBA_FontMap::Data::Data() = default; - -CBA_FontMap::Data::~Data() = default; - -CBA_FontMap::CBA_FontMap(CPDF_Document* pDocument, CPDF_Dictionary* pAnnotDict) - : m_pDocument(pDocument), m_pAnnotDict(pAnnotDict) { - Initialize(); -} - -CBA_FontMap::~CBA_FontMap() { - Clear(); -} - -RetainPtr<CPDF_Font> CBA_FontMap::GetPDFFont(int32_t nFontIndex) { - if (pdfium::IndexInBounds(m_Data, nFontIndex)) - return m_Data[nFontIndex]->pFont; - return nullptr; -} - -ByteString CBA_FontMap::GetPDFFontAlias(int32_t nFontIndex) { - if (pdfium::IndexInBounds(m_Data, nFontIndex)) - return m_Data[nFontIndex]->sFontName; - return ByteString(); -} - -int32_t CBA_FontMap::GetWordFontIndex(uint16_t word, - int32_t nCharset, - int32_t nFontIndex) { - if (nFontIndex > 0) { - if (KnowWord(nFontIndex, word)) - return nFontIndex; - } else { - if (!m_Data.empty()) { - const Data* pData = m_Data.front().get(); - if (nCharset == FX_CHARSET_Default || - pData->nCharset == FX_CHARSET_Symbol || nCharset == pData->nCharset) { - if (KnowWord(0, word)) - return 0; - } - } - } - - int32_t nNewFontIndex = - GetFontIndex(GetCachedNativeFontName(nCharset), nCharset, true); - if (nNewFontIndex >= 0) { - if (KnowWord(nNewFontIndex, word)) - return nNewFontIndex; - } - nNewFontIndex = GetFontIndex(CFX_Font::kUniversalDefaultFontName, - FX_CHARSET_Default, false); - if (nNewFontIndex >= 0) { - if (KnowWord(nNewFontIndex, word)) - return nNewFontIndex; - } - return -1; -} - -int32_t CBA_FontMap::CharCodeFromUnicode(int32_t nFontIndex, uint16_t word) { - if (!pdfium::IndexInBounds(m_Data, nFontIndex)) - return -1; - - Data* pData = m_Data[nFontIndex].get(); - if (!pData->pFont) - return -1; - - if (pData->pFont->IsUnicodeCompatible()) - return pData->pFont->CharCodeFromUnicode(word); - - return word < 0xFF ? word : -1; -} - -int32_t CBA_FontMap::CharSetFromUnicode(uint16_t word, int32_t nOldCharset) { - // to avoid CJK Font to show ASCII - if (word < 0x7F) - return FX_CHARSET_ANSI; - - // follow the old charset - if (nOldCharset != FX_CHARSET_Default) - return nOldCharset; - - return CFX_Font::GetCharSetFromUnicode(word); -} - -int32_t CBA_FontMap::GetNativeCharset() { - return FX_GetCharsetFromCodePage(FXSYS_GetACP()); -} - -void CBA_FontMap::Reset() { - Clear(); - m_pDefaultFont = nullptr; - m_sDefaultFontName.clear(); -} - -void CBA_FontMap::SetAPType(const ByteString& sAPType) { - m_sAPType = sAPType; - - Reset(); - Initialize(); -} - -void CBA_FontMap::Initialize() { - int32_t nCharset = FX_CHARSET_Default; - - if (!m_pDefaultFont) { - m_pDefaultFont = GetAnnotDefaultFont(&m_sDefaultFontName); - if (m_pDefaultFont) { - if (const CFX_SubstFont* pSubstFont = m_pDefaultFont->GetSubstFont()) { - nCharset = pSubstFont->m_Charset; - } else { - if (m_sDefaultFontName == "Wingdings" || - m_sDefaultFontName == "Wingdings2" || - m_sDefaultFontName == "Wingdings3" || - m_sDefaultFontName == "Webdings") - nCharset = FX_CHARSET_Symbol; - else - nCharset = FX_CHARSET_ANSI; - } - AddFontData(m_pDefaultFont, m_sDefaultFontName, nCharset); - AddFontToAnnotDict(m_pDefaultFont, m_sDefaultFontName); - } - } - - if (nCharset != FX_CHARSET_ANSI) - GetFontIndex(CFX_Font::kDefaultAnsiFontName, FX_CHARSET_ANSI, false); -} - -RetainPtr<CPDF_Font> CBA_FontMap::FindFontSameCharset(ByteString* sFontAlias, - int32_t nCharset) { - if (m_pAnnotDict->GetStringFor(pdfium::annotation::kSubtype) != "Widget") - return nullptr; - - const CPDF_Dictionary* pRootDict = m_pDocument->GetRoot(); - if (!pRootDict) - return nullptr; - - const CPDF_Dictionary* pAcroFormDict = pRootDict->GetDictFor("AcroForm"); - if (!pAcroFormDict) - return nullptr; - - const CPDF_Dictionary* pDRDict = pAcroFormDict->GetDictFor("DR"); - if (!pDRDict) - return nullptr; - - return FindResFontSameCharset(pDRDict, sFontAlias, nCharset); -} - -RetainPtr<CPDF_Font> CBA_FontMap::FindResFontSameCharset( - const CPDF_Dictionary* pResDict, - ByteString* sFontAlias, - int32_t nCharset) { - if (!pResDict) - return nullptr; - - const CPDF_Dictionary* pFonts = pResDict->GetDictFor("Font"); - if (!pFonts) - return nullptr; - - RetainPtr<CPDF_Font> pFind; - CPDF_DictionaryLocker locker(pFonts); - for (const auto& it : locker) { - const ByteString& csKey = it.first; - if (!it.second) - continue; - - CPDF_Dictionary* pElement = ToDictionary(it.second->GetDirect()); - if (!pElement || pElement->GetStringFor("Type") != "Font") - continue; - - auto* pData = CPDF_DocPageData::FromDocument(m_pDocument.Get()); - RetainPtr<CPDF_Font> pFont = pData->GetFont(pElement); - if (!pFont) - continue; - - const CFX_SubstFont* pSubst = pFont->GetSubstFont(); - if (!pSubst) - continue; - - if (pSubst->m_Charset == nCharset) { - *sFontAlias = csKey; - pFind = std::move(pFont); - } - } - return pFind; -} - -RetainPtr<CPDF_Font> CBA_FontMap::GetAnnotDefaultFont(ByteString* sAlias) { - CPDF_Dictionary* pAcroFormDict = nullptr; - const bool bWidget = - (m_pAnnotDict->GetStringFor(pdfium::annotation::kSubtype) == "Widget"); - if (bWidget) { - CPDF_Dictionary* pRootDict = m_pDocument->GetRoot(); - if (pRootDict) - pAcroFormDict = pRootDict->GetDictFor("AcroForm"); - } - - ByteString sDA; - const CPDF_Object* pObj = - CPDF_FormField::GetFieldAttr(m_pAnnotDict.Get(), "DA"); - if (pObj) - sDA = pObj->GetString(); - - if (bWidget) { - if (sDA.IsEmpty()) { - pObj = CPDF_FormField::GetFieldAttr(pAcroFormDict, "DA"); - sDA = pObj ? pObj->GetString() : ByteString(); - } - } - if (sDA.IsEmpty()) - return nullptr; - - CPDF_DefaultAppearance appearance(sDA); - float font_size; - Optional<ByteString> font = appearance.GetFont(&font_size); - *sAlias = font.value_or(ByteString()); - - CPDF_Dictionary* pFontDict = nullptr; - if (CPDF_Dictionary* pAPDict = - m_pAnnotDict->GetDictFor(pdfium::annotation::kAP)) { - if (CPDF_Dictionary* pNormalDict = pAPDict->GetDictFor("N")) { - if (CPDF_Dictionary* pNormalResDict = - pNormalDict->GetDictFor("Resources")) { - if (CPDF_Dictionary* pResFontDict = pNormalResDict->GetDictFor("Font")) - pFontDict = pResFontDict->GetDictFor(*sAlias); - } - } - } - if (bWidget && !pFontDict && pAcroFormDict) { - if (CPDF_Dictionary* pDRDict = pAcroFormDict->GetDictFor("DR")) { - if (CPDF_Dictionary* pDRFontDict = pDRDict->GetDictFor("Font")) - pFontDict = pDRFontDict->GetDictFor(*sAlias); - } - } - if (!pFontDict) - return nullptr; - - return CPDF_DocPageData::FromDocument(m_pDocument.Get())->GetFont(pFontDict); -} - -void CBA_FontMap::AddFontToAnnotDict(const RetainPtr<CPDF_Font>& pFont, - const ByteString& sAlias) { - if (!pFont) - return; - - CPDF_Dictionary* pAPDict = m_pAnnotDict->GetDictFor(pdfium::annotation::kAP); - if (!pAPDict) - pAPDict = m_pAnnotDict->SetNewFor<CPDF_Dictionary>(pdfium::annotation::kAP); - - // to avoid checkbox and radiobutton - if (ToDictionary(pAPDict->GetObjectFor(m_sAPType))) - return; - - CPDF_Stream* pStream = pAPDict->GetStreamFor(m_sAPType); - if (!pStream) { - pStream = m_pDocument->NewIndirect<CPDF_Stream>(); - pAPDict->SetNewFor<CPDF_Reference>(m_sAPType, m_pDocument.Get(), - pStream->GetObjNum()); - } - - CPDF_Dictionary* pStreamDict = pStream->GetDict(); - if (!pStreamDict) { - auto pOwnedDict = m_pDocument->New<CPDF_Dictionary>(); - pStreamDict = pOwnedDict.Get(); - pStream->InitStream({}, std::move(pOwnedDict)); - } - - CPDF_Dictionary* pStreamResList = pStreamDict->GetDictFor("Resources"); - if (!pStreamResList) - pStreamResList = pStreamDict->SetNewFor<CPDF_Dictionary>("Resources"); - CPDF_Dictionary* pStreamResFontList = pStreamResList->GetDictFor("Font"); - if (!pStreamResFontList) { - pStreamResFontList = m_pDocument->NewIndirect<CPDF_Dictionary>(); - pStreamResList->SetNewFor<CPDF_Reference>("Font", m_pDocument.Get(), - pStreamResFontList->GetObjNum()); - } - if (!pStreamResFontList->KeyExist(sAlias)) { - CPDF_Dictionary* pFontDict = pFont->GetFontDict(); - RetainPtr<CPDF_Object> pObject = - pFontDict->IsInline() ? pFontDict->Clone() - : pFontDict->MakeReference(m_pDocument.Get()); - pStreamResFontList->SetFor(sAlias, std::move(pObject)); - } -} - -bool CBA_FontMap::KnowWord(int32_t nFontIndex, uint16_t word) { - return pdfium::IndexInBounds(m_Data, nFontIndex) && - CharCodeFromUnicode(nFontIndex, word) >= 0; -} - -void CBA_FontMap::Clear() { - m_Data.clear(); - m_NativeFont.clear(); -} - -int32_t CBA_FontMap::GetFontIndex(const ByteString& sFontName, - int32_t nCharset, - bool bFind) { - int32_t nFontIndex = FindFont(EncodeFontAlias(sFontName, nCharset), nCharset); - if (nFontIndex >= 0) - return nFontIndex; - - ByteString sAlias; - RetainPtr<CPDF_Font> pFont = - bFind ? FindFontSameCharset(&sAlias, nCharset) : nullptr; - if (!pFont) { - ByteString sTemp = sFontName; - pFont = AddFontToDocument(sTemp, nCharset); - sAlias = EncodeFontAlias(sTemp, nCharset); - } - AddFontToAnnotDict(pFont, sAlias); - return AddFontData(pFont, sAlias, nCharset); -} - -int32_t CBA_FontMap::AddFontData(const RetainPtr<CPDF_Font>& pFont, - const ByteString& sFontAlias, - int32_t nCharset) { - auto pNewData = pdfium::MakeUnique<Data>(); - pNewData->pFont = pFont; - pNewData->sFontName = sFontAlias; - pNewData->nCharset = nCharset; - m_Data.push_back(std::move(pNewData)); - return pdfium::CollectionSize<int32_t>(m_Data) - 1; -} - -ByteString CBA_FontMap::EncodeFontAlias(const ByteString& sFontName, - int32_t nCharset) { - return EncodeFontAlias(sFontName) + ByteString::Format("_%02X", nCharset); -} - -ByteString CBA_FontMap::EncodeFontAlias(const ByteString& sFontName) { - ByteString sRet = sFontName; - sRet.Remove(' '); - return sRet; -} - -int32_t CBA_FontMap::FindFont(const ByteString& sFontName, int32_t nCharset) { - int32_t i = 0; - for (const auto& pData : m_Data) { - if ((nCharset == FX_CHARSET_Default || nCharset == pData->nCharset) && - (sFontName.IsEmpty() || pData->sFontName == sFontName)) { - return i; - } - ++i; - } - return -1; -} - -ByteString CBA_FontMap::GetNativeFontName(int32_t nCharset) { - if (nCharset == FX_CHARSET_Default) - nCharset = GetNativeCharset(); - - ByteString sFontName = CFX_Font::GetDefaultFontNameByCharset(nCharset); - if (!FindNativeTrueTypeFont(sFontName)) - return ByteString(); - - return sFontName; -} - -ByteString CBA_FontMap::GetCachedNativeFontName(int32_t nCharset) { - for (const auto& pData : m_NativeFont) { - if (pData && pData->nCharset == nCharset) - return pData->sFontName; - } - - ByteString sNew = GetNativeFontName(nCharset); - if (sNew.IsEmpty()) - return ByteString(); - - auto pNewData = pdfium::MakeUnique<Native>(); - pNewData->nCharset = nCharset; - pNewData->sFontName = sNew; - m_NativeFont.push_back(std::move(pNewData)); - return sNew; -} - -RetainPtr<CPDF_Font> CBA_FontMap::AddFontToDocument(ByteString sFontName, - uint8_t nCharset) { - if (IsStandardFont(sFontName)) - return AddStandardFont(sFontName); - - return AddSystemFont(sFontName, nCharset); -} - -bool CBA_FontMap::IsStandardFont(const ByteString& sFontName) { - static const char* const kStandardFontNames[] = {"Courier", - "Courier-Bold", - "Courier-BoldOblique", - "Courier-Oblique", - "Helvetica", - "Helvetica-Bold", - "Helvetica-BoldOblique", - "Helvetica-Oblique", - "Times-Roman", - "Times-Bold", - "Times-Italic", - "Times-BoldItalic", - "Symbol", - "ZapfDingbats"}; - for (const char* name : kStandardFontNames) { - if (sFontName == name) - return true; - } - return false; -} - -RetainPtr<CPDF_Font> CBA_FontMap::AddStandardFont(ByteString sFontName) { - auto* pPageData = CPDF_DocPageData::FromDocument(m_pDocument.Get()); - if (sFontName == "ZapfDingbats") - return pPageData->AddStandardFont(sFontName, nullptr); - - static const CPDF_FontEncoding fe(PDFFONT_ENCODING_WINANSI); - return pPageData->AddStandardFont(sFontName, &fe); -} - -RetainPtr<CPDF_Font> CBA_FontMap::AddSystemFont(ByteString sFontName, - uint8_t nCharset) { - if (sFontName.IsEmpty()) - sFontName = GetNativeFontName(nCharset); - - if (nCharset == FX_CHARSET_Default) - nCharset = GetNativeCharset(); - - return AddNativeTrueTypeFontToPDF(m_pDocument.Get(), sFontName, nCharset); -}
diff --git a/core/fpdfdoc/cba_fontmap.h b/core/fpdfdoc/cba_fontmap.h deleted file mode 100644 index 7130064..0000000 --- a/core/fpdfdoc/cba_fontmap.h +++ /dev/null
@@ -1,96 +0,0 @@ -// Copyright 2014 PDFium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com - -#ifndef CORE_FPDFDOC_CBA_FONTMAP_H_ -#define CORE_FPDFDOC_CBA_FONTMAP_H_ - -#include <memory> -#include <vector> - -#include "core/fpdfdoc/ipvt_fontmap.h" -#include "core/fxcrt/fx_codepage.h" -#include "core/fxcrt/retain_ptr.h" -#include "core/fxcrt/unowned_ptr.h" - -class CPDF_Dictionary; -class CPDF_Document; - -class CBA_FontMap final : public IPVT_FontMap { - public: - static int32_t GetNativeCharset(); - - CBA_FontMap(CPDF_Document* pDocument, CPDF_Dictionary* pAnnotDict); - ~CBA_FontMap() override; - - // IPVT_FontMap - RetainPtr<CPDF_Font> GetPDFFont(int32_t nFontIndex) override; - ByteString GetPDFFontAlias(int32_t nFontIndex) override; - int32_t GetWordFontIndex(uint16_t word, - int32_t nCharset, - int32_t nFontIndex) override; - int32_t CharCodeFromUnicode(int32_t nFontIndex, uint16_t word) override; - int32_t CharSetFromUnicode(uint16_t word, int32_t nOldCharset) override; - - void Reset(); - void SetAPType(const ByteString& sAPType); - - private: - struct Data { - Data(); - ~Data(); - - RetainPtr<CPDF_Font> pFont; - int32_t nCharset; - ByteString sFontName; - }; - - struct Native { - int32_t nCharset; - ByteString sFontName; - }; - - void Initialize(); - RetainPtr<CPDF_Font> FindFontSameCharset(ByteString* sFontAlias, - int32_t nCharset); - RetainPtr<CPDF_Font> FindResFontSameCharset(const CPDF_Dictionary* pResDict, - ByteString* sFontAlias, - int32_t nCharset); - RetainPtr<CPDF_Font> GetAnnotDefaultFont(ByteString* sAlias); - void AddFontToAnnotDict(const RetainPtr<CPDF_Font>& pFont, - const ByteString& sAlias); - - bool KnowWord(int32_t nFontIndex, uint16_t word); - - void Clear(); - int32_t GetFontIndex(const ByteString& sFontName, - int32_t nCharset, - bool bFind); - int32_t AddFontData(const RetainPtr<CPDF_Font>& pFont, - const ByteString& sFontAlias, - int32_t nCharset); - - ByteString EncodeFontAlias(const ByteString& sFontName, int32_t nCharset); - ByteString EncodeFontAlias(const ByteString& sFontName); - - int32_t FindFont(const ByteString& sFontName, int32_t nCharset); - ByteString GetNativeFontName(int32_t nCharset); - ByteString GetCachedNativeFontName(int32_t nCharset); - bool IsStandardFont(const ByteString& sFontName); - RetainPtr<CPDF_Font> AddFontToDocument(ByteString sFontName, - uint8_t nCharset); - RetainPtr<CPDF_Font> AddStandardFont(ByteString sFontName); - RetainPtr<CPDF_Font> AddSystemFont(ByteString sFontName, uint8_t nCharset); - - std::vector<std::unique_ptr<Data>> m_Data; - std::vector<std::unique_ptr<Native>> m_NativeFont; - UnownedPtr<CPDF_Document> const m_pDocument; - RetainPtr<CPDF_Dictionary> const m_pAnnotDict; - RetainPtr<CPDF_Font> m_pDefaultFont; - ByteString m_sDefaultFontName; - ByteString m_sAPType = "N"; -}; - -#endif // CORE_FPDFDOC_CBA_FONTMAP_H_
diff --git a/core/fpdfdoc/cline.cpp b/core/fpdfdoc/cline.cpp deleted file mode 100644 index 7940dc8..0000000 --- a/core/fpdfdoc/cline.cpp +++ /dev/null
@@ -1,38 +0,0 @@ -// Copyright 2016 PDFium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com - -#include "core/fpdfdoc/cline.h" - -CLine::CLine(const CPVT_LineInfo& lineinfo) : m_LineInfo(lineinfo) {} - -CLine::~CLine() = default; - -CPVT_WordPlace CLine::GetBeginWordPlace() const { - return CPVT_WordPlace(LinePlace.nSecIndex, LinePlace.nLineIndex, -1); -} - -CPVT_WordPlace CLine::GetEndWordPlace() const { - return CPVT_WordPlace(LinePlace.nSecIndex, LinePlace.nLineIndex, - m_LineInfo.nEndWordIndex); -} - -CPVT_WordPlace CLine::GetPrevWordPlace(const CPVT_WordPlace& place) const { - if (place.nWordIndex > m_LineInfo.nEndWordIndex) { - return CPVT_WordPlace(place.nSecIndex, place.nLineIndex, - m_LineInfo.nEndWordIndex); - } - return CPVT_WordPlace(place.nSecIndex, place.nLineIndex, - place.nWordIndex - 1); -} - -CPVT_WordPlace CLine::GetNextWordPlace(const CPVT_WordPlace& place) const { - if (place.nWordIndex < m_LineInfo.nBeginWordIndex) { - return CPVT_WordPlace(place.nSecIndex, place.nLineIndex, - m_LineInfo.nBeginWordIndex); - } - return CPVT_WordPlace(place.nSecIndex, place.nLineIndex, - place.nWordIndex + 1); -}
diff --git a/core/fpdfdoc/cline.h b/core/fpdfdoc/cline.h deleted file mode 100644 index b7e32d4..0000000 --- a/core/fpdfdoc/cline.h +++ /dev/null
@@ -1,26 +0,0 @@ -// Copyright 2016 PDFium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com - -#ifndef CORE_FPDFDOC_CLINE_H_ -#define CORE_FPDFDOC_CLINE_H_ - -#include "core/fpdfdoc/cpvt_lineinfo.h" -#include "core/fpdfdoc/cpvt_wordplace.h" - -class CLine { - public: - explicit CLine(const CPVT_LineInfo& lineinfo); - ~CLine(); - - CPVT_WordPlace GetBeginWordPlace() const; - CPVT_WordPlace GetEndWordPlace() const; - CPVT_WordPlace GetPrevWordPlace(const CPVT_WordPlace& place) const; - CPVT_WordPlace GetNextWordPlace(const CPVT_WordPlace& place) const; - CPVT_WordPlace LinePlace; - CPVT_LineInfo m_LineInfo; -}; - -#endif // CORE_FPDFDOC_CLINE_H_
diff --git a/core/fpdfdoc/cpdf_aaction.cpp b/core/fpdfdoc/cpdf_aaction.cpp index 8284913..4b62a7f 100644 --- a/core/fpdfdoc/cpdf_aaction.cpp +++ b/core/fpdfdoc/cpdf_aaction.cpp
@@ -1,4 +1,4 @@ -// Copyright 2016 PDFium Authors. All rights reserved. +// Copyright 2016 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -6,6 +6,9 @@ #include "core/fpdfdoc/cpdf_aaction.h" +#include <iterator> +#include <utility> + #include "core/fpdfapi/parser/cpdf_dictionary.h" namespace { @@ -36,12 +39,13 @@ // |kAATypes| should have one less element than enum AActionType due to // |kDocumentOpen|, which is an artificial type. -static_assert(FX_ArraySize(kAATypes) == CPDF_AAction::kNumberOfActions - 1, +static_assert(std::size(kAATypes) == CPDF_AAction::kNumberOfActions - 1, "kAATypes count mismatch"); } // namespace -CPDF_AAction::CPDF_AAction(const CPDF_Dictionary* pDict) : m_pDict(pDict) {} +CPDF_AAction::CPDF_AAction(RetainPtr<const CPDF_Dictionary> pDict) + : m_pDict(std::move(pDict)) {} CPDF_AAction::CPDF_AAction(const CPDF_AAction& that) = default; @@ -56,10 +60,11 @@ } // static -bool CPDF_AAction::IsUserClick(AActionType eType) { - switch (eType) { +bool CPDF_AAction::IsUserInput(AActionType type) { + switch (type) { case kButtonUp: case kButtonDown: + case kKeyStroke: return true; default: return false;
diff --git a/core/fpdfdoc/cpdf_aaction.h b/core/fpdfdoc/cpdf_aaction.h index c3c65e8..9b4cbcb 100644 --- a/core/fpdfdoc/cpdf_aaction.h +++ b/core/fpdfdoc/cpdf_aaction.h
@@ -1,4 +1,4 @@ -// Copyright 2016 PDFium Authors. All rights reserved. +// Copyright 2016 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -7,11 +7,10 @@ #ifndef CORE_FPDFDOC_CPDF_AACTION_H_ #define CORE_FPDFDOC_CPDF_AACTION_H_ +#include "core/fpdfapi/parser/cpdf_dictionary.h" #include "core/fpdfdoc/cpdf_action.h" #include "core/fxcrt/retain_ptr.h" -class CPDF_Dictionary; - class CPDF_AAction { public: enum AActionType { @@ -40,15 +39,15 @@ kNumberOfActions // Must be last. }; - explicit CPDF_AAction(const CPDF_Dictionary* pDict); + explicit CPDF_AAction(RetainPtr<const CPDF_Dictionary> pDict); CPDF_AAction(const CPDF_AAction& that); ~CPDF_AAction(); bool ActionExist(AActionType eType) const; CPDF_Action GetAction(AActionType eType) const; - const CPDF_Dictionary* GetDict() const { return m_pDict.Get(); } + bool HasDict() const { return !!m_pDict; } - static bool IsUserClick(AActionType eType); + static bool IsUserInput(AActionType type); private: RetainPtr<const CPDF_Dictionary> const m_pDict;
diff --git a/core/fpdfdoc/cpdf_action.cpp b/core/fpdfdoc/cpdf_action.cpp index 5133c1b..1370c7f 100644 --- a/core/fpdfdoc/cpdf_action.cpp +++ b/core/fpdfdoc/cpdf_action.cpp
@@ -1,4 +1,4 @@ -// Copyright 2016 PDFium Authors. All rights reserved. +// Copyright 2016 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -6,105 +6,94 @@ #include "core/fpdfdoc/cpdf_action.h" +#include <iterator> +#include <utility> + #include "constants/stream_dict_common.h" #include "core/fpdfapi/parser/cpdf_array.h" #include "core/fpdfapi/parser/cpdf_dictionary.h" #include "core/fpdfapi/parser/cpdf_document.h" #include "core/fpdfapi/parser/cpdf_name.h" +#include "core/fpdfapi/parser/fpdf_parser_utility.h" #include "core/fpdfdoc/cpdf_filespec.h" -#include "core/fpdfdoc/cpdf_nametree.h" namespace { -const char* const g_sATypes[] = { - "Unknown", "GoTo", "GoToR", "GoToE", "Launch", - "Thread", "URI", "Sound", "Movie", "Hide", - "Named", "SubmitForm", "ResetForm", "ImportData", "JavaScript", - "SetOCGState", "Rendition", "Trans", "GoTo3DView", nullptr}; +const char* const kActionTypeStrings[] = { + "GoTo", "GoToR", "GoToE", "Launch", "Thread", + "URI", "Sound", "Movie", "Hide", "Named", + "SubmitForm", "ResetForm", "ImportData", "JavaScript", "SetOCGState", + "Rendition", "Trans", "GoTo3DView"}; } // namespace -CPDF_Action::CPDF_Action(const CPDF_Dictionary* pDict) : m_pDict(pDict) {} +CPDF_Action::CPDF_Action(RetainPtr<const CPDF_Dictionary> pDict) + : m_pDict(std::move(pDict)) {} CPDF_Action::CPDF_Action(const CPDF_Action& that) = default; CPDF_Action::~CPDF_Action() = default; -CPDF_Action::ActionType CPDF_Action::GetType() const { - if (!m_pDict) - return Unknown; +CPDF_Action::Type CPDF_Action::GetType() const { + // See ISO 32000-1:2008 spec, table 193. + if (!ValidateDictOptionalType(m_pDict.Get(), "Action")) + return Type::kUnknown; - // Validate |m_pDict|. Type is optional, but must be valid if present. - const CPDF_Object* pType = m_pDict->GetObjectFor("Type"); - if (pType) { - const CPDF_Name* pName = pType->AsName(); - if (!pName || pName->GetString() != "Action") - return Unknown; - } - - ByteString csType = m_pDict->GetStringFor("S"); + ByteString csType = m_pDict->GetNameFor("S"); if (csType.IsEmpty()) - return Unknown; + return Type::kUnknown; - for (int i = 0; g_sATypes[i]; ++i) { - if (csType == g_sATypes[i]) - return static_cast<ActionType>(i); + static_assert( + std::size(kActionTypeStrings) == static_cast<size_t>(Type::kLast), + "Type mismatch"); + for (size_t i = 0; i < std::size(kActionTypeStrings); ++i) { + if (csType == kActionTypeStrings[i]) + return static_cast<Type>(i + 1); } - return Unknown; + return Type::kUnknown; } CPDF_Dest CPDF_Action::GetDest(CPDF_Document* pDoc) const { - ActionType type = GetType(); - if (type != GoTo && type != GoToR) - return CPDF_Dest(); - - const CPDF_Object* pDest = m_pDict->GetDirectObjectFor("D"); - if (!pDest) - return CPDF_Dest(); - if (pDest->IsString() || pDest->IsName()) { - CPDF_NameTree name_tree(pDoc, "Dests"); - return CPDF_Dest(name_tree.LookupNamedDest(pDoc, pDest->GetUnicodeText())); + Type type = GetType(); + if (type != Type::kGoTo && type != Type::kGoToR && type != Type::kGoToE) { + return CPDF_Dest(nullptr); } - if (const CPDF_Array* pArray = pDest->AsArray()) - return CPDF_Dest(pArray); - - return CPDF_Dest(); + return CPDF_Dest::Create(pDoc, m_pDict->GetDirectObjectFor("D")); } WideString CPDF_Action::GetFilePath() const { - ActionType type = GetType(); - if (type != GoToR && type != Launch && type != SubmitForm && - type != ImportData) { + Type type = GetType(); + if (type != Type::kGoToR && type != Type::kGoToE && type != Type::kLaunch && + type != Type::kSubmitForm && type != Type::kImportData) { return WideString(); } - const CPDF_Object* pFile = m_pDict->GetDirectObjectFor(pdfium::stream::kF); + RetainPtr<const CPDF_Object> pFile = + m_pDict->GetDirectObjectFor(pdfium::stream::kF); if (pFile) - return CPDF_FileSpec(pFile).GetFileName(); + return CPDF_FileSpec(std::move(pFile)).GetFileName(); - if (type != Launch) + if (type != Type::kLaunch) return WideString(); - const CPDF_Dictionary* pWinDict = m_pDict->GetDictFor("Win"); + RetainPtr<const CPDF_Dictionary> pWinDict = m_pDict->GetDictFor("Win"); if (!pWinDict) return WideString(); return WideString::FromDefANSI( - pWinDict->GetStringFor(pdfium::stream::kF).AsStringView()); + pWinDict->GetByteStringFor(pdfium::stream::kF).AsStringView()); } ByteString CPDF_Action::GetURI(const CPDF_Document* pDoc) const { - ActionType type = GetType(); - if (type != URI) + if (GetType() != Type::kURI) return ByteString(); - ByteString csURI = m_pDict->GetStringFor("URI"); - const CPDF_Dictionary* pRoot = pDoc->GetRoot(); - const CPDF_Dictionary* pURI = pRoot->GetDictFor("URI"); + ByteString csURI = m_pDict->GetByteStringFor("URI"); + RetainPtr<const CPDF_Dictionary> pURI = pDoc->GetRoot()->GetDictFor("URI"); if (pURI) { auto result = csURI.Find(":"); if (!result.has_value() || result.value() == 0) { - auto* pBase = pURI->GetDirectObjectFor("Base"); + RetainPtr<const CPDF_Object> pBase = pURI->GetDirectObjectFor("Base"); if (pBase && (pBase->IsString() || pBase->IsStream())) csURI = pBase->GetString() + csURI; } @@ -117,46 +106,55 @@ } ByteString CPDF_Action::GetNamedAction() const { - return m_pDict->GetStringFor("N"); + return m_pDict->GetByteStringFor("N"); } uint32_t CPDF_Action::GetFlags() const { return m_pDict->GetIntegerFor("Flags"); } -std::vector<const CPDF_Object*> CPDF_Action::GetAllFields() const { - std::vector<const CPDF_Object*> result; +bool CPDF_Action::HasFields() const { + return m_pDict->KeyExist("Fields"); +} + +std::vector<RetainPtr<const CPDF_Object>> CPDF_Action::GetAllFields() const { + std::vector<RetainPtr<const CPDF_Object>> result; if (!m_pDict) return result; - ByteString csType = m_pDict->GetStringFor("S"); - const CPDF_Object* pFields = csType == "Hide" - ? m_pDict->GetDirectObjectFor("T") - : m_pDict->GetArrayFor("Fields"); + ByteString csType = m_pDict->GetByteStringFor("S"); + RetainPtr<const CPDF_Object> pFields = csType == "Hide" + ? m_pDict->GetDirectObjectFor("T") + : m_pDict->GetArrayFor("Fields"); if (!pFields) return result; if (pFields->IsDictionary() || pFields->IsString()) { - result.push_back(pFields); - } else if (const CPDF_Array* pArray = pFields->AsArray()) { - for (size_t i = 0; i < pArray->size(); ++i) { - const CPDF_Object* pObj = pArray->GetDirectObjectAt(i); - if (pObj) - result.push_back(pObj); - } + result.push_back(std::move(pFields)); + return result; + } + + const CPDF_Array* pArray = pFields->AsArray(); + if (!pArray) + return result; + + for (size_t i = 0; i < pArray->size(); ++i) { + RetainPtr<const CPDF_Object> pObj = pArray->GetDirectObjectAt(i); + if (pObj) + result.push_back(std::move(pObj)); } return result; } -Optional<WideString> CPDF_Action::MaybeGetJavaScript() const { - const CPDF_Object* pObject = GetJavaScriptObject(); +absl::optional<WideString> CPDF_Action::MaybeGetJavaScript() const { + RetainPtr<const CPDF_Object> pObject = GetJavaScriptObject(); if (!pObject) - return pdfium::nullopt; + return absl::nullopt; return pObject->GetUnicodeText(); } WideString CPDF_Action::GetJavaScript() const { - const CPDF_Object* pObject = GetJavaScriptObject(); + RetainPtr<const CPDF_Object> pObject = GetJavaScriptObject(); return pObject ? pObject->GetUnicodeText() : WideString(); } @@ -164,7 +162,7 @@ if (!m_pDict || !m_pDict->KeyExist("Next")) return 0; - const CPDF_Object* pNext = m_pDict->GetDirectObjectFor("Next"); + RetainPtr<const CPDF_Object> pNext = m_pDict->GetDirectObjectFor("Next"); if (!pNext) return 0; if (pNext->IsDictionary()) @@ -177,20 +175,24 @@ if (!m_pDict || !m_pDict->KeyExist("Next")) return CPDF_Action(nullptr); - const CPDF_Object* pNext = m_pDict->GetDirectObjectFor("Next"); - if (const CPDF_Array* pArray = ToArray(pNext)) + RetainPtr<const CPDF_Object> pNext = m_pDict->GetDirectObjectFor("Next"); + if (!pNext) + return CPDF_Action(nullptr); + + if (const CPDF_Array* pArray = pNext->AsArray()) return CPDF_Action(pArray->GetDictAt(iIndex)); - if (const CPDF_Dictionary* pDict = ToDictionary(pNext)) { + + if (const CPDF_Dictionary* pDict = pNext->AsDictionary()) { if (iIndex == 0) - return CPDF_Action(pDict); + return CPDF_Action(pdfium::WrapRetain(pDict)); } return CPDF_Action(nullptr); } -const CPDF_Object* CPDF_Action::GetJavaScriptObject() const { +RetainPtr<const CPDF_Object> CPDF_Action::GetJavaScriptObject() const { if (!m_pDict) return nullptr; - const CPDF_Object* pJS = m_pDict->GetDirectObjectFor("JS"); + RetainPtr<const CPDF_Object> pJS = m_pDict->GetDirectObjectFor("JS"); return (pJS && (pJS->IsString() || pJS->IsStream())) ? pJS : nullptr; }
diff --git a/core/fpdfdoc/cpdf_action.h b/core/fpdfdoc/cpdf_action.h index c7cc2d8..cb9e930 100644 --- a/core/fpdfdoc/cpdf_action.h +++ b/core/fpdfdoc/cpdf_action.h
@@ -1,4 +1,4 @@ -// Copyright 2016 PDFium Authors. All rights reserved. +// Copyright 2016 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -12,7 +12,7 @@ #include "core/fpdfdoc/cpdf_dest.h" #include "core/fxcrt/fx_string.h" #include "core/fxcrt/retain_ptr.h" -#include "third_party/base/optional.h" +#include "third_party/abseil-cpp/absl/types/optional.h" class CPDF_Dictionary; class CPDF_Document; @@ -20,46 +20,49 @@ class CPDF_Action { public: - enum ActionType { - Unknown = 0, - GoTo, - GoToR, - GoToE, - Launch, - Thread, - URI, - Sound, - Movie, - Hide, - Named, - SubmitForm, - ResetForm, - ImportData, - JavaScript, - SetOCGState, - Rendition, - Trans, - GoTo3DView + enum class Type { + kUnknown = 0, + kGoTo, + kGoToR, + kGoToE, + kLaunch, + kThread, + kURI, + kSound, + kMovie, + kHide, + kNamed, + kSubmitForm, + kResetForm, + kImportData, + kJavaScript, + kSetOCGState, + kRendition, + kTrans, + kGoTo3DView, + kLast = kGoTo3DView }; - explicit CPDF_Action(const CPDF_Dictionary* pDict); + explicit CPDF_Action(RetainPtr<const CPDF_Dictionary> pDict); CPDF_Action(const CPDF_Action& that); ~CPDF_Action(); + bool HasDict() const { return !!m_pDict; } const CPDF_Dictionary* GetDict() const { return m_pDict.Get(); } - ActionType GetType() const; + Type GetType() const; CPDF_Dest GetDest(CPDF_Document* pDoc) const; WideString GetFilePath() const; ByteString GetURI(const CPDF_Document* pDoc) const; bool GetHideStatus() const; ByteString GetNamedAction() const; uint32_t GetFlags() const; + bool HasFields() const; - std::vector<const CPDF_Object*> GetAllFields() const; + std::vector<RetainPtr<const CPDF_Object>> GetAllFields() const; // Differentiates between empty JS entry and no JS entry. - Optional<WideString> MaybeGetJavaScript() const; + absl::optional<WideString> MaybeGetJavaScript() const; // Returns empty string for empty JS entry and no JS entry. WideString GetJavaScript() const; @@ -68,7 +71,7 @@ CPDF_Action GetSubAction(size_t iIndex) const; private: - const CPDF_Object* GetJavaScriptObject() const; + RetainPtr<const CPDF_Object> GetJavaScriptObject() const; RetainPtr<const CPDF_Dictionary> const m_pDict; };
diff --git a/core/fpdfdoc/cpdf_action_unittest.cpp b/core/fpdfdoc/cpdf_action_unittest.cpp new file mode 100644 index 0000000..a787711 --- /dev/null +++ b/core/fpdfdoc/cpdf_action_unittest.cpp
@@ -0,0 +1,127 @@ +// Copyright 2021 The PDFium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "core/fpdfdoc/cpdf_action.h" + +#include "core/fpdfapi/parser/cpdf_dictionary.h" +#include "core/fpdfapi/parser/cpdf_name.h" +#include "core/fpdfapi/parser/cpdf_string.h" +#include "core/fxcrt/retain_ptr.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace { + +RetainPtr<CPDF_Dictionary> CreateActionDictWithType( + const ByteString& action_type) { + auto dict = pdfium::MakeRetain<CPDF_Dictionary>(); + dict->SetNewFor<CPDF_Name>("Type", "Action"); + dict->SetNewFor<CPDF_Name>("S", action_type); + return dict; +} + +RetainPtr<CPDF_Dictionary> CreateActionDictWithoutType( + const ByteString& action_type) { + auto dict = pdfium::MakeRetain<CPDF_Dictionary>(); + dict->SetNewFor<CPDF_Name>("S", action_type); + return dict; +} + +RetainPtr<CPDF_Dictionary> CreateActionDictWithInvalidType( + const ByteString& action_type) { + auto dict = pdfium::MakeRetain<CPDF_Dictionary>(); + dict->SetNewFor<CPDF_Name>("Type", "Lights"); + dict->SetNewFor<CPDF_Name>("S", action_type); + return dict; +} + +RetainPtr<CPDF_Dictionary> CreateInvalidActionDictWithType( + const ByteString& action_type) { + auto dict = pdfium::MakeRetain<CPDF_Dictionary>(); + dict->SetNewFor<CPDF_Name>("Type", "Action"); + dict->SetNewFor<CPDF_String>("S", action_type, /*is_hex=*/false); + return dict; +} + +RetainPtr<CPDF_Dictionary> CreateInvalidActionDictWithoutType( + const ByteString& action_type) { + auto dict = pdfium::MakeRetain<CPDF_Dictionary>(); + dict->SetNewFor<CPDF_String>("S", action_type, /*is_hex=*/false); + return dict; +} + +} // namespace + +TEST(CPDFActionTest, GetType) { + static constexpr struct { + const char* action_type; + CPDF_Action::Type expected_type; + } kValidTestCases[] = { + {"GoTo", CPDF_Action::Type::kGoTo}, + {"GoToR", CPDF_Action::Type::kGoToR}, + {"GoToE", CPDF_Action::Type::kGoToE}, + {"Launch", CPDF_Action::Type::kLaunch}, + {"Thread", CPDF_Action::Type::kThread}, + {"URI", CPDF_Action::Type::kURI}, + {"Sound", CPDF_Action::Type::kSound}, + {"Movie", CPDF_Action::Type::kMovie}, + {"Hide", CPDF_Action::Type::kHide}, + {"Named", CPDF_Action::Type::kNamed}, + {"SubmitForm", CPDF_Action::Type::kSubmitForm}, + {"ResetForm", CPDF_Action::Type::kResetForm}, + {"ImportData", CPDF_Action::Type::kImportData}, + {"JavaScript", CPDF_Action::Type::kJavaScript}, + {"SetOCGState", CPDF_Action::Type::kSetOCGState}, + {"Rendition", CPDF_Action::Type::kRendition}, + {"Trans", CPDF_Action::Type::kTrans}, + {"GoTo3DView", CPDF_Action::Type::kGoTo3DView}, + }; + + // Test correctly constructed actions. + for (const auto& test_case : kValidTestCases) { + { + // Type is present. + CPDF_Action action(CreateActionDictWithType(test_case.action_type)); + EXPECT_EQ(test_case.expected_type, action.GetType()); + } + { + // Type is optional, so omitting it is ok. + CPDF_Action action(CreateActionDictWithoutType(test_case.action_type)); + EXPECT_EQ(test_case.expected_type, action.GetType()); + } + } + + // Test incorrectly constructed actions. + for (const auto& test_case : kValidTestCases) { + { + // Type is optional, but must be valid if present. + CPDF_Action action( + CreateActionDictWithInvalidType(test_case.action_type)); + EXPECT_EQ(CPDF_Action::Type::kUnknown, action.GetType()); + } + { + // The action type (/S) must be a name. + CPDF_Action action( + CreateInvalidActionDictWithType(test_case.action_type)); + EXPECT_EQ(CPDF_Action::Type::kUnknown, action.GetType()); + } + { + // The action type (/S) must be a name. + CPDF_Action action( + CreateInvalidActionDictWithoutType(test_case.action_type)); + EXPECT_EQ(CPDF_Action::Type::kUnknown, action.GetType()); + } + } + + static constexpr const char* kInvalidTestCases[] = { + "Camera", + "Javascript", + "Unknown", + }; + + // Test invalid actions. + for (const char* test_case : kInvalidTestCases) { + CPDF_Action action(CreateActionDictWithType(test_case)); + EXPECT_EQ(CPDF_Action::Type::kUnknown, action.GetType()); + } +}
diff --git a/core/fpdfdoc/cpdf_annot.cpp b/core/fpdfdoc/cpdf_annot.cpp index f474074..e0ecd88 100644 --- a/core/fpdfdoc/cpdf_annot.cpp +++ b/core/fpdfdoc/cpdf_annot.cpp
@@ -1,4 +1,4 @@ -// Copyright 2016 PDFium Authors. All rights reserved. +// Copyright 2016 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -13,19 +13,21 @@ #include "constants/annotation_flags.h" #include "core/fpdfapi/page/cpdf_form.h" #include "core/fpdfapi/page/cpdf_page.h" +#include "core/fpdfapi/page/cpdf_pageimagecache.h" #include "core/fpdfapi/parser/cpdf_array.h" #include "core/fpdfapi/parser/cpdf_boolean.h" #include "core/fpdfapi/parser/cpdf_dictionary.h" #include "core/fpdfapi/parser/cpdf_document.h" +#include "core/fpdfapi/parser/cpdf_stream.h" #include "core/fpdfapi/parser/fpdf_parser_utility.h" -#include "core/fpdfapi/render/cpdf_pagerendercache.h" #include "core/fpdfapi/render/cpdf_rendercontext.h" #include "core/fpdfapi/render/cpdf_renderoptions.h" -#include "core/fpdfdoc/cpvt_generateap.h" +#include "core/fpdfdoc/cpdf_generateap.h" +#include "core/fxge/cfx_fillrenderoptions.h" #include "core/fxge/cfx_graphstatedata.h" -#include "core/fxge/cfx_pathdata.h" +#include "core/fxge/cfx_path.h" #include "core/fxge/cfx_renderdevice.h" -#include "third_party/base/ptr_util.h" +#include "third_party/base/check.h" namespace { @@ -38,10 +40,10 @@ type == CPDF_Annot::Subtype::UNDERLINE; } -CPDF_Form* AnnotGetMatrix(const CPDF_Page* pPage, +CPDF_Form* AnnotGetMatrix(CPDF_Page* pPage, CPDF_Annot* pAnnot, CPDF_Annot::AppearanceMode mode, - const CFX_Matrix* pUser2Device, + const CFX_Matrix& mtUser2Device, CFX_Matrix* matrix) { CPDF_Form* pForm = pAnnot->GetAPForm(pPage, mode); if (!pForm) @@ -51,77 +53,88 @@ CFX_FloatRect form_bbox = form_matrix.TransformRect(pForm->GetDict()->GetRectFor("BBox")); matrix->MatchRect(pAnnot->GetRect(), form_bbox); - matrix->Concat(*pUser2Device); + + // Compensate for page rotation. + if ((pAnnot->GetFlags() & pdfium::annotation_flags::kNoRotate) && + pPage->GetPageRotation() != 0) { + // Rotate annotation rect around top-left angle (according to the + // specification). + const float offset_x = pAnnot->GetRect().Left(); + const float offset_y = pAnnot->GetRect().Top(); + matrix->Concat({1, 0, 0, 1, -offset_x, -offset_y}); + // GetPageRotation returns value in fractions of pi/2. + const float angle = FXSYS_PI / 2 * pPage->GetPageRotation(); + matrix->Rotate(angle); + matrix->Concat({1, 0, 0, 1, offset_x, offset_y}); + } + + matrix->Concat(mtUser2Device); return pForm; } -CPDF_Stream* GetAnnotAPInternal(CPDF_Dictionary* pAnnotDict, - CPDF_Annot::AppearanceMode eMode, - bool bFallbackToNormal) { - CPDF_Dictionary* pAP = pAnnotDict->GetDictFor(pdfium::annotation::kAP); +RetainPtr<CPDF_Stream> GetAnnotAPInternal(CPDF_Dictionary* pAnnotDict, + CPDF_Annot::AppearanceMode eMode, + bool bFallbackToNormal) { + RetainPtr<CPDF_Dictionary> pAP = + pAnnotDict->GetMutableDictFor(pdfium::annotation::kAP); if (!pAP) return nullptr; const char* ap_entry = "N"; - if (eMode == CPDF_Annot::Down) + if (eMode == CPDF_Annot::AppearanceMode::kDown) ap_entry = "D"; - else if (eMode == CPDF_Annot::Rollover) + else if (eMode == CPDF_Annot::AppearanceMode::kRollover) ap_entry = "R"; if (bFallbackToNormal && !pAP->KeyExist(ap_entry)) ap_entry = "N"; - CPDF_Object* psub = pAP->GetDirectObjectFor(ap_entry); + RetainPtr<CPDF_Object> psub = pAP->GetMutableDirectObjectFor(ap_entry); if (!psub) return nullptr; - if (CPDF_Stream* pStream = psub->AsStream()) + + RetainPtr<CPDF_Stream> pStream(psub->AsMutableStream()); + if (pStream) return pStream; - CPDF_Dictionary* pDict = psub->AsDictionary(); + CPDF_Dictionary* pDict = psub->AsMutableDictionary(); if (!pDict) return nullptr; - ByteString as = pAnnotDict->GetStringFor(pdfium::annotation::kAS); + ByteString as = pAnnotDict->GetByteStringFor(pdfium::annotation::kAS); if (as.IsEmpty()) { - ByteString value = pAnnotDict->GetStringFor("V"); + ByteString value = pAnnotDict->GetByteStringFor("V"); if (value.IsEmpty()) { - const CPDF_Dictionary* pParentDict = pAnnotDict->GetDictFor("Parent"); - value = pParentDict ? pParentDict->GetStringFor("V") : ByteString(); + RetainPtr<const CPDF_Dictionary> pParentDict = + pAnnotDict->GetDictFor("Parent"); + value = pParentDict ? pParentDict->GetByteStringFor("V") : ByteString(); } as = (!value.IsEmpty() && pDict->KeyExist(value)) ? value : "Off"; } - return pDict->GetStreamFor(as); + return pDict->GetMutableStreamFor(as); } } // namespace CPDF_Annot::CPDF_Annot(RetainPtr<CPDF_Dictionary> pDict, CPDF_Document* pDocument) - : m_pAnnotDict(std::move(pDict)), m_pDocument(pDocument) { - Init(); -} - -CPDF_Annot::CPDF_Annot(CPDF_Dictionary* pDict, CPDF_Document* pDocument) - : m_pAnnotDict(pDict), m_pDocument(pDocument) { - Init(); + : m_pAnnotDict(std::move(pDict)), + m_pDocument(pDocument), + m_nSubtype(StringToAnnotSubtype( + m_pAnnotDict->GetByteStringFor(pdfium::annotation::kSubtype))), + m_bIsTextMarkupAnnotation(IsTextMarkupAnnotation(m_nSubtype)), + m_bHasGeneratedAP( + m_pAnnotDict->GetBooleanFor(kPDFiumKey_HasGeneratedAP, false)) { + GenerateAPIfNeeded(); } CPDF_Annot::~CPDF_Annot() { ClearCachedAP(); } -void CPDF_Annot::Init() { - m_nSubtype = StringToAnnotSubtype( - m_pAnnotDict->GetStringFor(pdfium::annotation::kSubtype)); - m_bIsTextMarkupAnnotation = IsTextMarkupAnnotation(m_nSubtype); - m_bHasGeneratedAP = - m_pAnnotDict->GetBooleanFor(kPDFiumKey_HasGeneratedAP, false); - GenerateAPIfNeeded(); -} - void CPDF_Annot::GenerateAPIfNeeded() { if (!ShouldGenerateAP()) return; - if (!CPVT_GenerateAP::GenerateAnnotAP(m_pDocument.Get(), m_pAnnotDict.Get(), + if (!CPDF_GenerateAP::GenerateAnnotAP(m_pDocument, m_pAnnotDict.Get(), m_nSubtype)) { return; } @@ -133,7 +146,7 @@ bool CPDF_Annot::ShouldGenerateAP() const { // If AP dictionary exists and defines an appearance for normal mode, we use // the appearance defined in the existing AP dictionary. - const CPDF_Dictionary* pAP = + RetainPtr<const CPDF_Dictionary> pAP = m_pAnnotDict->GetDictFor(pdfium::annotation::kAP); if (pAP && pAP->GetDictFor("N")) return false; @@ -177,20 +190,20 @@ return !!(GetFlags() & pdfium::annotation_flags::kHidden); } -CPDF_Stream* GetAnnotAP(CPDF_Dictionary* pAnnotDict, - CPDF_Annot::AppearanceMode eMode) { - ASSERT(pAnnotDict); +RetainPtr<CPDF_Stream> GetAnnotAP(CPDF_Dictionary* pAnnotDict, + CPDF_Annot::AppearanceMode eMode) { + DCHECK(pAnnotDict); return GetAnnotAPInternal(pAnnotDict, eMode, true); } -CPDF_Stream* GetAnnotAPNoFallback(CPDF_Dictionary* pAnnotDict, - CPDF_Annot::AppearanceMode eMode) { - ASSERT(pAnnotDict); +RetainPtr<CPDF_Stream> GetAnnotAPNoFallback(CPDF_Dictionary* pAnnotDict, + CPDF_Annot::AppearanceMode eMode) { + DCHECK(pAnnotDict); return GetAnnotAPInternal(pAnnotDict, eMode, false); } -CPDF_Form* CPDF_Annot::GetAPForm(const CPDF_Page* pPage, AppearanceMode mode) { - CPDF_Stream* pStream = GetAnnotAP(m_pAnnotDict.Get(), mode); +CPDF_Form* CPDF_Annot::GetAPForm(CPDF_Page* pPage, AppearanceMode mode) { + RetainPtr<CPDF_Stream> pStream = GetAnnotAP(m_pAnnotDict.Get(), mode); if (!pStream) return nullptr; @@ -198,8 +211,8 @@ if (it != m_APMap.end()) return it->second.get(); - auto pNewForm = pdfium::MakeUnique<CPDF_Form>( - m_pDocument.Get(), pPage->m_pResources.Get(), pStream); + auto pNewForm = std::make_unique<CPDF_Form>( + m_pDocument, pPage->GetMutableResources(), pStream); pNewForm->ParseContent(); CPDF_Form* pResult = pNewForm.get(); @@ -207,11 +220,22 @@ return pResult; } +void CPDF_Annot::SetPopupAnnotOpenState(bool bOpenState) { + if (m_pPopupAnnot) + m_pPopupAnnot->SetOpenState(bOpenState); +} + +absl::optional<CFX_FloatRect> CPDF_Annot::GetPopupAnnotRect() const { + if (!m_pPopupAnnot) + return absl::nullopt; + return m_pPopupAnnot->GetRect(); +} + // static CFX_FloatRect CPDF_Annot::RectFromQuadPointsArray(const CPDF_Array* pArray, size_t nIndex) { - ASSERT(pArray); - ASSERT(nIndex < pArray->size() / 8); + DCHECK(pArray); + DCHECK(nIndex < pArray->size() / 8); // QuadPoints are defined with 4 pairs of numbers // ([ pair0, pair1, pair2, pair3 ]), where @@ -225,22 +249,22 @@ // pair1 = top_right. return CFX_FloatRect( - pArray->GetNumberAt(4 + nIndex * 8), pArray->GetNumberAt(5 + nIndex * 8), - pArray->GetNumberAt(2 + nIndex * 8), pArray->GetNumberAt(3 + nIndex * 8)); + pArray->GetFloatAt(4 + nIndex * 8), pArray->GetFloatAt(5 + nIndex * 8), + pArray->GetFloatAt(2 + nIndex * 8), pArray->GetFloatAt(3 + nIndex * 8)); } // static CFX_FloatRect CPDF_Annot::BoundingRectFromQuadPoints( const CPDF_Dictionary* pAnnotDict) { CFX_FloatRect ret; - const CPDF_Array* pArray = pAnnotDict->GetArrayFor("QuadPoints"); - size_t nQuadPointCount = pArray ? QuadPointCount(pArray) : 0; + RetainPtr<const CPDF_Array> pArray = pAnnotDict->GetArrayFor("QuadPoints"); + size_t nQuadPointCount = pArray ? QuadPointCount(pArray.Get()) : 0; if (nQuadPointCount == 0) return ret; - ret = RectFromQuadPointsArray(pArray, 0); + ret = RectFromQuadPointsArray(pArray.Get(), 0); for (size_t i = 1; i < nQuadPointCount; ++i) { - CFX_FloatRect rect = RectFromQuadPointsArray(pArray, i); + CFX_FloatRect rect = RectFromQuadPointsArray(pArray.Get(), i); ret.Union(rect); } return ret; @@ -249,11 +273,11 @@ // static CFX_FloatRect CPDF_Annot::RectFromQuadPoints(const CPDF_Dictionary* pAnnotDict, size_t nIndex) { - const CPDF_Array* pArray = pAnnotDict->GetArrayFor("QuadPoints"); - size_t nQuadPointCount = pArray ? QuadPointCount(pArray) : 0; + RetainPtr<const CPDF_Array> pArray = pAnnotDict->GetArrayFor("QuadPoints"); + size_t nQuadPointCount = pArray ? QuadPointCount(pArray.Get()) : 0; if (nIndex >= nQuadPointCount) return CFX_FloatRect(); - return RectFromQuadPointsArray(pArray, nIndex); + return RectFromQuadPointsArray(pArray.Get(), nIndex); } // static @@ -313,6 +337,8 @@ return CPDF_Annot::Subtype::RICHMEDIA; if (sSubtype == "XFAWidget") return CPDF_Annot::Subtype::XFAWIDGET; + if (sSubtype == "Redact") + return CPDF_Annot::Subtype::REDACT; return CPDF_Annot::Subtype::UNKNOWN; } @@ -372,6 +398,8 @@ return "RichMedia"; if (nSubtype == CPDF_Annot::Subtype::XFAWIDGET) return "XFAWidget"; + if (nSubtype == CPDF_Annot::Subtype::REDACT) + return "Redact"; return ByteString(); } @@ -383,57 +411,55 @@ bool CPDF_Annot::DrawAppearance(CPDF_Page* pPage, CFX_RenderDevice* pDevice, const CFX_Matrix& mtUser2Device, - AppearanceMode mode, - const CPDF_RenderOptions* pOptions) { + AppearanceMode mode) { if (!ShouldDrawAnnotation()) return false; // It might happen that by the time this annotation instance was created, - // it was flagged as "hidden" (e.g. /F 2), and hence CPVT_GenerateAP decided + // it was flagged as "hidden" (e.g. /F 2), and hence CPDF_GenerateAP decided // to not "generate" its AP. // If for a reason the object is no longer hidden, but still does not have // its "AP" generated, generate it now. GenerateAPIfNeeded(); CFX_Matrix matrix; - CPDF_Form* pForm = AnnotGetMatrix(pPage, this, mode, &mtUser2Device, &matrix); + CPDF_Form* pForm = AnnotGetMatrix(pPage, this, mode, mtUser2Device, &matrix); if (!pForm) return false; - CPDF_RenderContext context( - pPage->GetDocument(), pPage->m_pPageResources.Get(), - static_cast<CPDF_PageRenderCache*>(pPage->GetRenderCache())); - context.AppendLayer(pForm, &matrix); - context.Render(pDevice, pOptions, nullptr); + CPDF_RenderContext context(pPage->GetDocument(), + pPage->GetMutablePageResources(), + pPage->GetPageImageCache()); + context.AppendLayer(pForm, matrix); + context.Render(pDevice, nullptr, nullptr, nullptr); return true; } -bool CPDF_Annot::DrawInContext(const CPDF_Page* pPage, +bool CPDF_Annot::DrawInContext(CPDF_Page* pPage, CPDF_RenderContext* pContext, - const CFX_Matrix* pUser2Device, + const CFX_Matrix& mtUser2Device, AppearanceMode mode) { if (!ShouldDrawAnnotation()) return false; // It might happen that by the time this annotation instance was created, - // it was flagged as "hidden" (e.g. /F 2), and hence CPVT_GenerateAP decided + // it was flagged as "hidden" (e.g. /F 2), and hence CPDF_GenerateAP decided // to not "generate" its AP. // If for a reason the object is no longer hidden, but still does not have // its "AP" generated, generate it now. GenerateAPIfNeeded(); CFX_Matrix matrix; - CPDF_Form* pForm = AnnotGetMatrix(pPage, this, mode, pUser2Device, &matrix); + CPDF_Form* pForm = AnnotGetMatrix(pPage, this, mode, mtUser2Device, &matrix); if (!pForm) return false; - pContext->AppendLayer(pForm, &matrix); + pContext->AppendLayer(pForm, matrix); return true; } void CPDF_Annot::DrawBorder(CFX_RenderDevice* pDevice, - const CFX_Matrix* pUser2Device, - const CPDF_RenderOptions* pOptions) { + const CFX_Matrix* pUser2Device) { if (GetSubtype() == CPDF_Annot::Subtype::POPUP) return; @@ -441,24 +467,23 @@ if (annot_flags & pdfium::annotation_flags::kHidden) return; - bool bPrinting = pDevice->GetDeviceType() == DeviceType::kPrinter || - (pOptions && pOptions->GetOptions().bPrintPreview); + bool bPrinting = pDevice->GetDeviceType() == DeviceType::kPrinter; if (bPrinting && (annot_flags & pdfium::annotation_flags::kPrint) == 0) { return; } if (!bPrinting && (annot_flags & pdfium::annotation_flags::kNoView)) { return; } - CPDF_Dictionary* pBS = m_pAnnotDict->GetDictFor("BS"); + RetainPtr<const CPDF_Dictionary> pBS = m_pAnnotDict->GetDictFor("BS"); char style_char; float width; - CPDF_Array* pDashArray = nullptr; + RetainPtr<const CPDF_Array> pDashArray; if (!pBS) { - CPDF_Array* pBorderArray = + RetainPtr<const CPDF_Array> pBorderArray = m_pAnnotDict->GetArrayFor(pdfium::annotation::kBorder); style_char = 'S'; if (pBorderArray) { - width = pBorderArray->GetNumberAt(2); + width = pBorderArray->GetFloatAt(2); if (pBorderArray->size() == 4) { pDashArray = pBorderArray->GetArrayAt(3); if (!pDashArray) { @@ -467,7 +492,7 @@ size_t nLen = pDashArray->size(); size_t i = 0; for (; i < nLen; ++i) { - CPDF_Object* pObj = pDashArray->GetDirectObjectAt(i); + RetainPtr<const CPDF_Object> pObj = pDashArray->GetDirectObjectAt(i); if (pObj && pObj->GetInteger()) { break; } @@ -481,28 +506,35 @@ width = 1; } } else { - ByteString style = pBS->GetStringFor("S"); + ByteString style = pBS->GetByteStringFor("S"); pDashArray = pBS->GetArrayFor("D"); - style_char = style[1]; - width = pBS->GetNumberFor("W"); + style_char = style[0]; + width = pBS->GetFloatFor("W"); } if (width <= 0) { return; } - CPDF_Array* pColor = m_pAnnotDict->GetArrayFor(pdfium::annotation::kC); + RetainPtr<const CPDF_Array> pColor = + m_pAnnotDict->GetArrayFor(pdfium::annotation::kC); uint32_t argb = 0xff000000; if (pColor) { - int R = (int32_t)(pColor->GetNumberAt(0) * 255); - int G = (int32_t)(pColor->GetNumberAt(1) * 255); - int B = (int32_t)(pColor->GetNumberAt(2) * 255); + int R = static_cast<int32_t>(pColor->GetFloatAt(0) * 255); + int G = static_cast<int32_t>(pColor->GetFloatAt(1) * 255); + int B = static_cast<int32_t>(pColor->GetFloatAt(2) * 255); argb = ArgbEncode(0xff, R, G, B); } CFX_GraphStateData graph_state; graph_state.m_LineWidth = width; + if (style_char == 'U') { + // TODO(https://crbug.com/237527): Handle the "Underline" border style + // instead of drawing the rectangle border. + return; + } + if (style_char == 'D') { if (pDashArray) { graph_state.m_DashArray = - ReadArrayElementsToVector(pDashArray, pDashArray->size()); + ReadArrayElementsToVector(pDashArray.Get(), pDashArray->size()); if (graph_state.m_DashArray.size() % 2) graph_state.m_DashArray.push_back(graph_state.m_DashArray.back()); } else { @@ -512,12 +544,9 @@ CFX_FloatRect rect = GetRect(); rect.Deflate(width / 2, width / 2); - CFX_PathData path; + + CFX_Path path; path.AppendFloatRect(rect); - - int fill_type = 0; - if (pOptions && pOptions->GetOptions().bNoPathSmooth) - fill_type |= FXFILL_NOPATHSMOOTH; - - pDevice->DrawPath(&path, pUser2Device, &graph_state, argb, argb, fill_type); + pDevice->DrawPath(path, pUser2Device, &graph_state, argb, argb, + CFX_FillRenderOptions()); }
diff --git a/core/fpdfdoc/cpdf_annot.h b/core/fpdfdoc/cpdf_annot.h index 64ab69d..4f8b2f8 100644 --- a/core/fpdfdoc/cpdf_annot.h +++ b/core/fpdfdoc/cpdf_annot.h
@@ -1,4 +1,4 @@ -// Copyright 2016 PDFium Authors. All rights reserved. +// Copyright 2016 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -7,13 +7,19 @@ #ifndef CORE_FPDFDOC_CPDF_ANNOT_H_ #define CORE_FPDFDOC_CPDF_ANNOT_H_ +#include <stddef.h> +#include <stdint.h> + #include <map> #include <memory> +#include "core/fpdfapi/parser/cpdf_stream.h" +#include "core/fxcrt/bytestring.h" #include "core/fxcrt/fx_coordinates.h" -#include "core/fxcrt/fx_string.h" -#include "core/fxcrt/fx_system.h" #include "core/fxcrt/maybe_owned.h" +#include "core/fxcrt/retain_ptr.h" +#include "core/fxcrt/unowned_ptr.h" +#include "third_party/abseil-cpp/absl/types/optional.h" class CFX_RenderDevice; class CPDF_Array; @@ -22,13 +28,11 @@ class CPDF_Form; class CPDF_Page; class CPDF_RenderContext; -class CPDF_RenderOptions; -class CPDF_Stream; class CPDF_Annot { public: - enum AppearanceMode { Normal, Rollover, Down }; - enum class Subtype { + enum class AppearanceMode { kNormal, kRollover, kDown }; + enum class Subtype : uint8_t { UNKNOWN = 0, TEXT, LINK, @@ -56,11 +60,12 @@ WATERMARK, THREED, RICHMEDIA, - XFAWIDGET + XFAWIDGET, + REDACT }; - static CPDF_Annot::Subtype StringToAnnotSubtype(const ByteString& sSubtype); - static ByteString AnnotSubtypeToString(CPDF_Annot::Subtype nSubtype); + static Subtype StringToAnnotSubtype(const ByteString& sSubtype); + static ByteString AnnotSubtypeToString(Subtype nSubtype); static CFX_FloatRect RectFromQuadPointsArray(const CPDF_Array* pArray, size_t nIndex); static CFX_FloatRect BoundingRectFromQuadPoints( @@ -69,41 +74,35 @@ size_t nIndex); static size_t QuadPointCount(const CPDF_Array* pArray); - // The second constructor does not take ownership of the dictionary. CPDF_Annot(RetainPtr<CPDF_Dictionary> pDict, CPDF_Document* pDocument); - CPDF_Annot(CPDF_Dictionary* pDict, CPDF_Document* pDocument); ~CPDF_Annot(); - CPDF_Annot::Subtype GetSubtype() const; + Subtype GetSubtype() const; uint32_t GetFlags() const; CFX_FloatRect GetRect() const; - CPDF_Document* GetDocument() const { return m_pDocument.Get(); } const CPDF_Dictionary* GetAnnotDict() const { return m_pAnnotDict.Get(); } - CPDF_Dictionary* GetAnnotDict() { return m_pAnnotDict.Get(); } + RetainPtr<CPDF_Dictionary> GetMutableAnnotDict() { return m_pAnnotDict; } bool IsHidden() const; bool DrawAppearance(CPDF_Page* pPage, CFX_RenderDevice* pDevice, const CFX_Matrix& mtUser2Device, - AppearanceMode mode, - const CPDF_RenderOptions* pOptions); - bool DrawInContext(const CPDF_Page* pPage, + AppearanceMode mode); + bool DrawInContext(CPDF_Page* pPage, CPDF_RenderContext* pContext, - const CFX_Matrix* pUser2Device, + const CFX_Matrix& mtUser2Device, AppearanceMode mode); void ClearCachedAP(); - void DrawBorder(CFX_RenderDevice* pDevice, - const CFX_Matrix* pUser2Device, - const CPDF_RenderOptions* pOptions); - CPDF_Form* GetAPForm(const CPDF_Page* pPage, AppearanceMode mode); + void DrawBorder(CFX_RenderDevice* pDevice, const CFX_Matrix* pUser2Device); + CPDF_Form* GetAPForm(CPDF_Page* pPage, AppearanceMode mode); void SetOpenState(bool bOpenState) { m_bOpenState = bOpenState; } - CPDF_Annot* GetPopupAnnot() const { return m_pPopupAnnot.Get(); } + void SetPopupAnnotOpenState(bool bOpenState); + absl::optional<CFX_FloatRect> GetPopupAnnotRect() const; void SetPopupAnnot(CPDF_Annot* pAnnot) { m_pPopupAnnot = pAnnot; } private: - void Init(); void GenerateAPIfNeeded(); bool ShouldGenerateAP() const; bool ShouldDrawAnnotation() const; @@ -112,25 +111,25 @@ RetainPtr<CPDF_Dictionary> const m_pAnnotDict; UnownedPtr<CPDF_Document> const m_pDocument; - CPDF_Annot::Subtype m_nSubtype; - std::map<CPDF_Stream*, std::unique_ptr<CPDF_Form>> m_APMap; + std::map<RetainPtr<CPDF_Stream>, std::unique_ptr<CPDF_Form>> m_APMap; // If non-null, then this is not a popup annotation. UnownedPtr<CPDF_Annot> m_pPopupAnnot; + const Subtype m_nSubtype; + const bool m_bIsTextMarkupAnnotation; // |m_bOpenState| is only set for popup annotations. bool m_bOpenState = false; bool m_bHasGeneratedAP; - bool m_bIsTextMarkupAnnotation; }; // Get the AP in an annotation dict for a given appearance mode. // If |eMode| is not Normal and there is not AP for that mode, falls back to // the Normal AP. -CPDF_Stream* GetAnnotAP(CPDF_Dictionary* pAnnotDict, - CPDF_Annot::AppearanceMode eMode); +RetainPtr<CPDF_Stream> GetAnnotAP(CPDF_Dictionary* pAnnotDict, + CPDF_Annot::AppearanceMode eMode); // Get the AP in an annotation dict for a given appearance mode. // No fallbacks to Normal like in GetAnnotAP. -CPDF_Stream* GetAnnotAPNoFallback(CPDF_Dictionary* pAnnotDict, - CPDF_Annot::AppearanceMode eMode); +RetainPtr<CPDF_Stream> GetAnnotAPNoFallback(CPDF_Dictionary* pAnnotDict, + CPDF_Annot::AppearanceMode eMode); #endif // CORE_FPDFDOC_CPDF_ANNOT_H_
diff --git a/core/fpdfdoc/cpdf_annot_unittest.cpp b/core/fpdfdoc/cpdf_annot_unittest.cpp index a7625e9..a988719 100644 --- a/core/fpdfdoc/cpdf_annot_unittest.cpp +++ b/core/fpdfdoc/cpdf_annot_unittest.cpp
@@ -1,10 +1,9 @@ -// Copyright 2018 PDFium Authors. All rights reserved. +// Copyright 2018 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "core/fpdfdoc/cpdf_annot.h" -#include <memory> #include <vector> #include "core/fpdfapi/parser/cpdf_array.h" @@ -18,7 +17,7 @@ const std::vector<int>& points) { auto array = pdfium::MakeRetain<CPDF_Array>(); for (float point : points) - array->AddNew<CPDF_Number>(point); + array->AppendNew<CPDF_Number>(point); return array; } @@ -124,14 +123,14 @@ EXPECT_EQ(0u, CPDF_Annot::QuadPointCount(array.Get())); for (int i = 0; i < 7; ++i) { - array->AddNew<CPDF_Number>(0); + array->AppendNew<CPDF_Number>(0); EXPECT_EQ(0u, CPDF_Annot::QuadPointCount(array.Get())); } for (int i = 0; i < 8; ++i) { - array->AddNew<CPDF_Number>(0); + array->AppendNew<CPDF_Number>(0); EXPECT_EQ(1u, CPDF_Annot::QuadPointCount(array.Get())); } for (int i = 0; i < 50; ++i) - array->AddNew<CPDF_Number>(0); + array->AppendNew<CPDF_Number>(0); EXPECT_EQ(8u, CPDF_Annot::QuadPointCount(array.Get())); }
diff --git a/core/fpdfdoc/cpdf_annotlist.cpp b/core/fpdfdoc/cpdf_annotlist.cpp index 37208e3..f565a5a 100644 --- a/core/fpdfdoc/cpdf_annotlist.cpp +++ b/core/fpdfdoc/cpdf_annotlist.cpp
@@ -1,4 +1,4 @@ -// Copyright 2016 PDFium Authors. All rights reserved. +// Copyright 2016 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -26,10 +26,9 @@ #include "core/fpdfapi/render/cpdf_renderoptions.h" #include "core/fpdfdoc/cpdf_annot.h" #include "core/fpdfdoc/cpdf_formfield.h" +#include "core/fpdfdoc/cpdf_generateap.h" #include "core/fpdfdoc/cpdf_interactiveform.h" -#include "core/fpdfdoc/cpvt_generateap.h" #include "core/fxge/cfx_renderdevice.h" -#include "third_party/base/ptr_util.h" namespace { @@ -49,6 +48,7 @@ case CPDF_Annot::Subtype::CARET: case CPDF_Annot::Subtype::INK: case CPDF_Annot::Subtype::FILEATTACHMENT: + case CPDF_Annot::Subtype::REDACT: return true; case CPDF_Annot::Subtype::UNKNOWN: case CPDF_Annot::Subtype::LINK: @@ -91,7 +91,7 @@ pAnnotDict->SetNewFor<CPDF_Name>(pdfium::annotation::kSubtype, "Popup"); pAnnotDict->SetNewFor<CPDF_String>( pdfium::form_fields::kT, - pParentDict->GetStringFor(pdfium::form_fields::kT), false); + pParentDict->GetByteStringFor(pdfium::form_fields::kT), false); pAnnotDict->SetNewFor<CPDF_String>(pdfium::annotation::kContents, sContents.ToUTF8(), false); @@ -117,37 +117,37 @@ pAnnotDict->SetNewFor<CPDF_Number>(pdfium::annotation::kF, 0); auto pPopupAnnot = - pdfium::MakeUnique<CPDF_Annot>(std::move(pAnnotDict), pDocument); + std::make_unique<CPDF_Annot>(std::move(pAnnotDict), pDocument); pAnnot->SetPopupAnnot(pPopupAnnot.get()); return pPopupAnnot; } void GenerateAP(CPDF_Document* pDoc, CPDF_Dictionary* pAnnotDict) { if (!pAnnotDict || - pAnnotDict->GetStringFor(pdfium::annotation::kSubtype) != "Widget") { + pAnnotDict->GetByteStringFor(pdfium::annotation::kSubtype) != "Widget") { return; } - CPDF_Object* pFieldTypeObj = - CPDF_FormField::GetFieldAttr(pAnnotDict, pdfium::form_fields::kFT); + RetainPtr<const CPDF_Object> pFieldTypeObj = + CPDF_FormField::GetFieldAttrForDict(pAnnotDict, pdfium::form_fields::kFT); if (!pFieldTypeObj) return; ByteString field_type = pFieldTypeObj->GetString(); if (field_type == pdfium::form_fields::kTx) { - CPVT_GenerateAP::GenerateFormAP(pDoc, pAnnotDict, - CPVT_GenerateAP::kTextField); + CPDF_GenerateAP::GenerateFormAP(pDoc, pAnnotDict, + CPDF_GenerateAP::kTextField); return; } - CPDF_Object* pFieldFlagsObj = - CPDF_FormField::GetFieldAttr(pAnnotDict, pdfium::form_fields::kFf); + RetainPtr<const CPDF_Object> pFieldFlagsObj = + CPDF_FormField::GetFieldAttrForDict(pAnnotDict, pdfium::form_fields::kFf); uint32_t flags = pFieldFlagsObj ? pFieldFlagsObj->GetInteger() : 0; if (field_type == pdfium::form_fields::kCh) { auto type = (flags & pdfium::form_flags::kChoiceCombo) - ? CPVT_GenerateAP::kComboBox - : CPVT_GenerateAP::kListBox; - CPVT_GenerateAP::GenerateFormAP(pDoc, pAnnotDict, type); + ? CPDF_GenerateAP::kComboBox + : CPDF_GenerateAP::kListBox; + CPDF_GenerateAP::GenerateFormAP(pDoc, pAnnotDict, type); return; } @@ -158,53 +158,53 @@ if (pAnnotDict->KeyExist(pdfium::annotation::kAS)) return; - CPDF_Dictionary* pParentDict = + RetainPtr<const CPDF_Dictionary> pParentDict = pAnnotDict->GetDictFor(pdfium::form_fields::kParent); if (!pParentDict || !pParentDict->KeyExist(pdfium::annotation::kAS)) return; pAnnotDict->SetNewFor<CPDF_String>( pdfium::annotation::kAS, - pParentDict->GetStringFor(pdfium::annotation::kAS), false); + pParentDict->GetByteStringFor(pdfium::annotation::kAS), false); } } // namespace CPDF_AnnotList::CPDF_AnnotList(CPDF_Page* pPage) : m_pDocument(pPage->GetDocument()) { - CPDF_Array* pAnnots = pPage->GetDict()->GetArrayFor("Annots"); + RetainPtr<CPDF_Array> pAnnots = pPage->GetMutableAnnotsArray(); if (!pAnnots) return; const CPDF_Dictionary* pRoot = m_pDocument->GetRoot(); - const CPDF_Dictionary* pAcroForm = pRoot->GetDictFor("AcroForm"); + RetainPtr<const CPDF_Dictionary> pAcroForm = pRoot->GetDictFor("AcroForm"); bool bRegenerateAP = pAcroForm && pAcroForm->GetBooleanFor("NeedAppearances", false); for (size_t i = 0; i < pAnnots->size(); ++i) { - CPDF_Dictionary* pDict = ToDictionary(pAnnots->GetDirectObjectAt(i)); + RetainPtr<CPDF_Dictionary> pDict = + ToDictionary(pAnnots->GetMutableDirectObjectAt(i)); if (!pDict) continue; const ByteString subtype = - pDict->GetStringFor(pdfium::annotation::kSubtype); + pDict->GetByteStringFor(pdfium::annotation::kSubtype); if (subtype == "Popup") { // Skip creating Popup annotations in the PDF document since PDFium // provides its own Popup annotations. continue; } - pAnnots->ConvertToIndirectObjectAt(i, m_pDocument.Get()); - m_AnnotList.push_back( - pdfium::MakeUnique<CPDF_Annot>(pDict, m_pDocument.Get())); + pAnnots->ConvertToIndirectObjectAt(i, m_pDocument); + m_AnnotList.push_back(std::make_unique<CPDF_Annot>(pDict, m_pDocument)); if (bRegenerateAP && subtype == "Widget" && CPDF_InteractiveForm::IsUpdateAPEnabled() && !pDict->GetDictFor(pdfium::annotation::kAP)) { - GenerateAP(m_pDocument.Get(), pDict); + GenerateAP(m_pDocument, pDict.Get()); } } m_nAnnotCount = m_AnnotList.size(); for (size_t i = 0; i < m_nAnnotCount; ++i) { std::unique_ptr<CPDF_Annot> pPopupAnnot = - CreatePopupAnnot(m_pDocument.Get(), pPage, m_AnnotList[i].get()); + CreatePopupAnnot(m_pDocument, pPage, m_AnnotList[i].get()); if (pPopupAnnot) m_AnnotList.push_back(std::move(pPopupAnnot)); } @@ -221,14 +221,20 @@ m_AnnotList.clear(); } +bool CPDF_AnnotList::Contains(const CPDF_Annot* pAnnot) const { + auto it = std::find_if(m_AnnotList.begin(), m_AnnotList.end(), + [pAnnot](const std::unique_ptr<CPDF_Annot>& annot) { + return annot.get() == pAnnot; + }); + return it != m_AnnotList.end(); +} + void CPDF_AnnotList::DisplayPass(CPDF_Page* pPage, CFX_RenderDevice* pDevice, CPDF_RenderContext* pContext, bool bPrinting, - const CFX_Matrix* pMatrix, - bool bWidgetPass, - CPDF_RenderOptions* pOptions, - FX_RECT* clip_rect) { + const CFX_Matrix& mtMatrix, + bool bWidgetPass) { for (const auto& pAnnot : m_AnnotList) { bool bWidget = pAnnot->GetSubtype() == CPDF_Annot::Subtype::WIDGET; if ((bWidgetPass && !bWidget) || (!bWidgetPass && bWidget)) @@ -244,29 +250,12 @@ if (!bPrinting && (annot_flags & pdfium::annotation_flags::kNoView)) continue; - if (pOptions) { - const CPDF_Dictionary* pAnnotDict = pAnnot->GetAnnotDict(); - const CPDF_OCContext* pOCContext = pOptions->GetOCContext(); - if (pAnnotDict && pOCContext && - !pOCContext->CheckOCGVisible( - pAnnotDict->GetDictFor(pdfium::annotation::kOC))) { - continue; - } - } - - CFX_Matrix matrix = *pMatrix; - if (clip_rect) { - FX_RECT annot_rect = - matrix.TransformRect(pAnnot->GetRect()).GetOuterRect(); - annot_rect.Intersect(*clip_rect); - if (annot_rect.IsEmpty()) - continue; - } if (pContext) { - pAnnot->DrawInContext(pPage, pContext, &matrix, CPDF_Annot::Normal); - } else if (!pAnnot->DrawAppearance(pPage, pDevice, matrix, - CPDF_Annot::Normal, pOptions)) { - pAnnot->DrawBorder(pDevice, &matrix, pOptions); + pAnnot->DrawInContext(pPage, pContext, mtMatrix, + CPDF_Annot::AppearanceMode::kNormal); + } else if (!pAnnot->DrawAppearance(pPage, pDevice, mtMatrix, + CPDF_Annot::AppearanceMode::kNormal)) { + pAnnot->DrawBorder(pDevice, &mtMatrix); } } } @@ -275,29 +264,9 @@ CFX_RenderDevice* pDevice, CPDF_RenderContext* pContext, bool bPrinting, - const CFX_Matrix* pUser2Device, - uint32_t dwAnnotFlags, - CPDF_RenderOptions* pOptions, - FX_RECT* pClipRect) { - if (dwAnnotFlags & pdfium::annotation_flags::kInvisible) { - DisplayPass(pPage, pDevice, pContext, bPrinting, pUser2Device, false, - pOptions, pClipRect); - } - if (dwAnnotFlags & pdfium::annotation_flags::kHidden) { - DisplayPass(pPage, pDevice, pContext, bPrinting, pUser2Device, true, - pOptions, pClipRect); - } -} - -void CPDF_AnnotList::DisplayAnnots(CPDF_Page* pPage, - CPDF_RenderContext* pContext, - bool bPrinting, - const CFX_Matrix* pMatrix, - bool bShowWidget, - CPDF_RenderOptions* pOptions) { - uint32_t dwAnnotFlags = bShowWidget ? pdfium::annotation_flags::kInvisible | - pdfium::annotation_flags::kHidden - : pdfium::annotation_flags::kInvisible; - DisplayAnnots(pPage, nullptr, pContext, bPrinting, pMatrix, dwAnnotFlags, - pOptions, nullptr); + const CFX_Matrix& mtUser2Device, + bool bShowWidget) { + DisplayPass(pPage, pDevice, pContext, bPrinting, mtUser2Device, false); + if (bShowWidget) + DisplayPass(pPage, pDevice, pContext, bPrinting, mtUser2Device, true); }
diff --git a/core/fpdfdoc/cpdf_annotlist.h b/core/fpdfdoc/cpdf_annotlist.h index 85075cf..ff98c8a 100644 --- a/core/fpdfdoc/cpdf_annotlist.h +++ b/core/fpdfdoc/cpdf_annotlist.h
@@ -1,4 +1,4 @@ -// Copyright 2016 PDFium Authors. All rights reserved. +// Copyright 2016 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -7,12 +7,14 @@ #ifndef CORE_FPDFDOC_CPDF_ANNOTLIST_H_ #define CORE_FPDFDOC_CPDF_ANNOTLIST_H_ +#include <stddef.h> +#include <stdint.h> + #include <memory> #include <vector> #include "core/fpdfapi/render/cpdf_pagerendercontext.h" #include "core/fxcrt/fx_coordinates.h" -#include "core/fxcrt/fx_system.h" #include "core/fxcrt/unowned_ptr.h" class CFX_RenderDevice; @@ -20,44 +22,30 @@ class CPDF_Document; class CPDF_Page; class CPDF_RenderContext; -class CPDF_RenderOptions; -class CPDF_AnnotList : public CPDF_PageRenderContext::AnnotListIface { +class CPDF_AnnotList final : public CPDF_PageRenderContext::AnnotListIface { public: explicit CPDF_AnnotList(CPDF_Page* pPage); ~CPDF_AnnotList() override; void DisplayAnnots(CPDF_Page* pPage, - CPDF_RenderContext* pContext, - bool bPrinting, - const CFX_Matrix* pMatrix, - bool bShowWidget, - CPDF_RenderOptions* pOptions); - - void DisplayAnnots(CPDF_Page* pPage, CFX_RenderDevice* pDevice, CPDF_RenderContext* pContext, bool bPrinting, - const CFX_Matrix* pUser2Device, - uint32_t dwAnnotFlags, - CPDF_RenderOptions* pOptions, - FX_RECT* pClipRect); + const CFX_Matrix& mtUser2Device, + bool bShowWidget); size_t Count() const { return m_AnnotList.size(); } CPDF_Annot* GetAt(size_t index) const { return m_AnnotList[index].get(); } - const std::vector<std::unique_ptr<CPDF_Annot>>& All() const { - return m_AnnotList; - } + bool Contains(const CPDF_Annot* pAnnot) const; private: void DisplayPass(CPDF_Page* pPage, CFX_RenderDevice* pDevice, CPDF_RenderContext* pContext, bool bPrinting, - const CFX_Matrix* pMatrix, - bool bWidget, - CPDF_RenderOptions* pOptions, - FX_RECT* clip_rect); + const CFX_Matrix& mtMatrix, + bool bWidget); UnownedPtr<CPDF_Document> const m_pDocument;
diff --git a/core/fpdfdoc/cpdf_apsettings.cpp b/core/fpdfdoc/cpdf_apsettings.cpp index 341764f..e7cd305 100644 --- a/core/fpdfdoc/cpdf_apsettings.cpp +++ b/core/fpdfdoc/cpdf_apsettings.cpp
@@ -1,4 +1,4 @@ -// Copyright 2016 PDFium Authors. All rights reserved. +// Copyright 2016 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -7,17 +7,19 @@ #include "core/fpdfdoc/cpdf_apsettings.h" #include <algorithm> +#include <utility> #include "core/fpdfapi/parser/cpdf_array.h" #include "core/fpdfapi/parser/cpdf_dictionary.h" +#include "core/fpdfapi/parser/cpdf_stream.h" #include "core/fpdfdoc/cpdf_formcontrol.h" -#include "core/fxge/cfx_color.h" -CPDF_ApSettings::CPDF_ApSettings(CPDF_Dictionary* pDict) : m_pDict(pDict) {} +CPDF_ApSettings::CPDF_ApSettings(RetainPtr<CPDF_Dictionary> pDict) + : m_pDict(std::move(pDict)) {} CPDF_ApSettings::CPDF_ApSettings(const CPDF_ApSettings& that) = default; -CPDF_ApSettings::~CPDF_ApSettings() {} +CPDF_ApSettings::~CPDF_ApSettings() = default; bool CPDF_ApSettings::HasMKEntry(const ByteString& csEntry) const { return m_pDict && m_pDict->KeyExist(csEntry); @@ -27,91 +29,80 @@ return m_pDict ? m_pDict->GetIntegerFor("R") : 0; } -FX_ARGB CPDF_ApSettings::GetColor(int& iColorType, - const ByteString& csEntry) const { - iColorType = CFX_Color::kTransparent; +CFX_Color::TypeAndARGB CPDF_ApSettings::GetColorARGB( + const ByteString& csEntry) const { if (!m_pDict) - return 0; + return {CFX_Color::Type::kTransparent, 0}; - CPDF_Array* pEntry = m_pDict->GetArrayFor(csEntry); + RetainPtr<const CPDF_Array> pEntry = m_pDict->GetArrayFor(csEntry); if (!pEntry) - return 0; + return {CFX_Color::Type::kTransparent, 0}; - FX_ARGB color = 0; - size_t dwCount = pEntry->size(); + const size_t dwCount = pEntry->size(); if (dwCount == 1) { - iColorType = CFX_Color::kGray; - float g = pEntry->GetNumberAt(0) * 255; - return ArgbEncode(255, (int)g, (int)g, (int)g); + const float g = pEntry->GetFloatAt(0) * 255; + return {CFX_Color::Type::kGray, ArgbEncode(255, (int)g, (int)g, (int)g)}; } if (dwCount == 3) { - iColorType = CFX_Color::kRGB; - float r = pEntry->GetNumberAt(0) * 255; - float g = pEntry->GetNumberAt(1) * 255; - float b = pEntry->GetNumberAt(2) * 255; - return ArgbEncode(255, (int)r, (int)g, (int)b); + float r = pEntry->GetFloatAt(0) * 255; + float g = pEntry->GetFloatAt(1) * 255; + float b = pEntry->GetFloatAt(2) * 255; + return {CFX_Color::Type::kRGB, ArgbEncode(255, (int)r, (int)g, (int)b)}; } if (dwCount == 4) { - iColorType = CFX_Color::kCMYK; - float c = pEntry->GetNumberAt(0); - float m = pEntry->GetNumberAt(1); - float y = pEntry->GetNumberAt(2); - float k = pEntry->GetNumberAt(3); - float r = 1.0f - std::min(1.0f, c + k); - float g = 1.0f - std::min(1.0f, m + k); - float b = 1.0f - std::min(1.0f, y + k); - return ArgbEncode(255, (int)(r * 255), (int)(g * 255), (int)(b * 255)); + float c = pEntry->GetFloatAt(0); + float m = pEntry->GetFloatAt(1); + float y = pEntry->GetFloatAt(2); + float k = pEntry->GetFloatAt(3); + float r = (1.0f - std::min(1.0f, c + k)) * 255; + float g = (1.0f - std::min(1.0f, m + k)) * 255; + float b = (1.0f - std::min(1.0f, y + k)) * 255; + return {CFX_Color::Type::kCMYK, ArgbEncode(255, (int)r, (int)g, (int)b)}; } - return color; + return {CFX_Color::Type::kTransparent, 0}; } -float CPDF_ApSettings::GetOriginalColor(int index, - const ByteString& csEntry) const { +float CPDF_ApSettings::GetOriginalColorComponent( + int index, + const ByteString& csEntry) const { if (!m_pDict) return 0; - CPDF_Array* pEntry = m_pDict->GetArrayFor(csEntry); - return pEntry ? pEntry->GetNumberAt(index) : 0; + RetainPtr<const CPDF_Array> pEntry = m_pDict->GetArrayFor(csEntry); + return pEntry ? pEntry->GetFloatAt(index) : 0; } -void CPDF_ApSettings::GetOriginalColor(int& iColorType, - float fc[4], - const ByteString& csEntry) const { - iColorType = CFX_Color::kTransparent; - for (int i = 0; i < 4; i++) - fc[i] = 0; - +CFX_Color CPDF_ApSettings::GetOriginalColor(const ByteString& csEntry) const { if (!m_pDict) - return; + return CFX_Color(); - CPDF_Array* pEntry = m_pDict->GetArrayFor(csEntry); + RetainPtr<const CPDF_Array> pEntry = m_pDict->GetArrayFor(csEntry); if (!pEntry) - return; + return CFX_Color(); size_t dwCount = pEntry->size(); if (dwCount == 1) { - iColorType = CFX_Color::kGray; - fc[0] = pEntry->GetNumberAt(0); - } else if (dwCount == 3) { - iColorType = CFX_Color::kRGB; - fc[0] = pEntry->GetNumberAt(0); - fc[1] = pEntry->GetNumberAt(1); - fc[2] = pEntry->GetNumberAt(2); - } else if (dwCount == 4) { - iColorType = CFX_Color::kCMYK; - fc[0] = pEntry->GetNumberAt(0); - fc[1] = pEntry->GetNumberAt(1); - fc[2] = pEntry->GetNumberAt(2); - fc[3] = pEntry->GetNumberAt(3); + return CFX_Color(CFX_Color::Type::kGray, pEntry->GetFloatAt(0)); } + if (dwCount == 3) { + return CFX_Color(CFX_Color::Type::kRGB, pEntry->GetFloatAt(0), + pEntry->GetFloatAt(1), pEntry->GetFloatAt(2)); + } + if (dwCount == 4) { + return CFX_Color(CFX_Color::Type::kCMYK, pEntry->GetFloatAt(0), + pEntry->GetFloatAt(1), pEntry->GetFloatAt(2), + pEntry->GetFloatAt(3)); + } + return CFX_Color(); } WideString CPDF_ApSettings::GetCaption(const ByteString& csEntry) const { return m_pDict ? m_pDict->GetUnicodeTextFor(csEntry) : WideString(); } -CPDF_Stream* CPDF_ApSettings::GetIcon(const ByteString& csEntry) const { - return m_pDict ? m_pDict->GetStreamFor(csEntry) : nullptr; +RetainPtr<CPDF_Stream> CPDF_ApSettings::GetIcon( + const ByteString& csEntry) const { + return m_pDict ? m_pDict->GetMutableStreamFor(csEntry) : nullptr; } CPDF_IconFit CPDF_ApSettings::GetIconFit() const {
diff --git a/core/fpdfdoc/cpdf_apsettings.h b/core/fpdfdoc/cpdf_apsettings.h index 2a16336..31e8e60 100644 --- a/core/fpdfdoc/cpdf_apsettings.h +++ b/core/fpdfdoc/cpdf_apsettings.h
@@ -1,4 +1,4 @@ -// Copyright 2016 PDFium Authors. All rights reserved. +// Copyright 2016 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -9,12 +9,11 @@ #include "core/fpdfdoc/cpdf_iconfit.h" #include "core/fxcrt/fx_string.h" -#include "core/fxcrt/fx_system.h" #include "core/fxcrt/retain_ptr.h" -#include "core/fxge/fx_dib.h" +#include "core/fxge/cfx_color.h" +#include "core/fxge/dib/fx_dib.h" class CPDF_Dictionary; -class CPDF_FormControl; class CPDF_Stream; // Corresponds to PDF spec section 12.5.6.19 (Widget annotation TP dictionary). @@ -28,56 +27,25 @@ class CPDF_ApSettings { public: - explicit CPDF_ApSettings(CPDF_Dictionary* pDict); + explicit CPDF_ApSettings(RetainPtr<CPDF_Dictionary> pDict); CPDF_ApSettings(const CPDF_ApSettings& that); ~CPDF_ApSettings(); bool HasMKEntry(const ByteString& csEntry) const; int GetRotation() const; - FX_ARGB GetBorderColor(int& iColorType) const { - return GetColor(iColorType, "BC"); - } - - float GetOriginalBorderColor(int index) const { - return GetOriginalColor(index, "BC"); - } - - void GetOriginalBorderColor(int& iColorType, float fc[4]) const { - GetOriginalColor(iColorType, fc, "BC"); - } - - FX_ARGB GetBackgroundColor(int& iColorType) const { - return GetColor(iColorType, "BG"); - } - - float GetOriginalBackgroundColor(int index) const { - return GetOriginalColor(index, "BG"); - } - - void GetOriginalBackgroundColor(int& iColorType, float fc[4]) const { - GetOriginalColor(iColorType, fc, "BG"); - } - - WideString GetNormalCaption() const { return GetCaption("CA"); } - WideString GetRolloverCaption() const { return GetCaption("RC"); } - WideString GetDownCaption() const { return GetCaption("AC"); } - CPDF_Stream* GetNormalIcon() const { return GetIcon("I"); } - CPDF_Stream* GetRolloverIcon() const { return GetIcon("RI"); } - CPDF_Stream* GetDownIcon() const { return GetIcon("IX"); } CPDF_IconFit GetIconFit() const; // Returns one of the TEXTPOS_* values above. int GetTextPosition() const; - FX_ARGB GetColor(int& iColorType, const ByteString& csEntry) const; - float GetOriginalColor(int index, const ByteString& csEntry) const; - void GetOriginalColor(int& iColorType, - float fc[4], - const ByteString& csEntry) const; + CFX_Color::TypeAndARGB GetColorARGB(const ByteString& csEntry) const; + + float GetOriginalColorComponent(int index, const ByteString& csEntry) const; + CFX_Color GetOriginalColor(const ByteString& csEntry) const; WideString GetCaption(const ByteString& csEntry) const; - CPDF_Stream* GetIcon(const ByteString& csEntry) const; + RetainPtr<CPDF_Stream> GetIcon(const ByteString& csEntry) const; private: RetainPtr<CPDF_Dictionary> const m_pDict;
diff --git a/core/fpdfdoc/cpdf_bafontmap.cpp b/core/fpdfdoc/cpdf_bafontmap.cpp new file mode 100644 index 0000000..c8617bb --- /dev/null +++ b/core/fpdfdoc/cpdf_bafontmap.cpp
@@ -0,0 +1,432 @@ +// Copyright 2014 The PDFium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com + +#include "core/fpdfdoc/cpdf_bafontmap.h" + +#include <memory> +#include <utility> + +#include "constants/annotation_common.h" +#include "core/fpdfapi/font/cpdf_font.h" +#include "core/fpdfapi/font/cpdf_fontencoding.h" +#include "core/fpdfapi/page/cpdf_docpagedata.h" +#include "core/fpdfapi/page/cpdf_page.h" +#include "core/fpdfapi/parser/cpdf_dictionary.h" +#include "core/fpdfapi/parser/cpdf_document.h" +#include "core/fpdfapi/parser/cpdf_parser.h" +#include "core/fpdfapi/parser/cpdf_reference.h" +#include "core/fpdfapi/parser/cpdf_stream.h" +#include "core/fpdfapi/parser/fpdf_parser_utility.h" +#include "core/fpdfdoc/cpdf_defaultappearance.h" +#include "core/fpdfdoc/cpdf_formfield.h" +#include "core/fpdfdoc/ipvt_fontmap.h" +#include "core/fxcrt/fx_codepage.h" +#include "core/fxcrt/stl_util.h" +#include "core/fxge/cfx_fontmapper.h" +#include "core/fxge/cfx_fontmgr.h" +#include "core/fxge/cfx_gemodule.h" + +namespace { + +bool FindNativeTrueTypeFont(ByteStringView sFontFaceName) { + CFX_FontMgr* pFontMgr = CFX_GEModule::Get()->GetFontMgr(); + CFX_FontMapper* pFontMapper = pFontMgr->GetBuiltinMapper(); + pFontMapper->LoadInstalledFonts(); + return pFontMapper->HasInstalledFont(sFontFaceName) || + pFontMapper->HasLocalizedFont(sFontFaceName); +} + +RetainPtr<CPDF_Font> AddNativeTrueTypeFontToPDF(CPDF_Document* pDoc, + ByteString sFontFaceName, + FX_Charset nCharset) { + if (!pDoc) + return nullptr; + + auto pFXFont = std::make_unique<CFX_Font>(); + pFXFont->LoadSubst(sFontFaceName, true, 0, 0, 0, + FX_GetCodePageFromCharset(nCharset), false); + + auto* pDocPageData = CPDF_DocPageData::FromDocument(pDoc); + return pDocPageData->AddFont(std::move(pFXFont), nCharset); +} + +ByteString EncodeFontAlias(ByteString sFontName, FX_Charset nCharset) { + sFontName.Remove(' '); + sFontName += ByteString::Format("_%02X", nCharset); + return sFontName; +} + +} // namespace + +CPDF_BAFontMap::Data::Data() = default; + +CPDF_BAFontMap::Data::~Data() = default; + +CPDF_BAFontMap::CPDF_BAFontMap(CPDF_Document* pDocument, + RetainPtr<CPDF_Dictionary> pAnnotDict, + const ByteString& sAPType) + : m_pDocument(pDocument), + m_pAnnotDict(std::move(pAnnotDict)), + m_sAPType(sAPType) { + FX_Charset nCharset = FX_Charset::kDefault; + m_pDefaultFont = GetAnnotDefaultFont(&m_sDefaultFontName); + if (m_pDefaultFont) { + auto maybe_charset = m_pDefaultFont->GetSubstFontCharset(); + if (maybe_charset.has_value()) { + nCharset = maybe_charset.value(); + } else if (m_sDefaultFontName == "Wingdings" || + m_sDefaultFontName == "Wingdings2" || + m_sDefaultFontName == "Wingdings3" || + m_sDefaultFontName == "Webdings") { + nCharset = FX_Charset::kSymbol; + } else { + nCharset = FX_Charset::kANSI; + } + AddFontData(m_pDefaultFont, m_sDefaultFontName, nCharset); + AddFontToAnnotDict(m_pDefaultFont, m_sDefaultFontName); + } + + if (nCharset != FX_Charset::kANSI) + GetFontIndex(CFX_Font::kDefaultAnsiFontName, FX_Charset::kANSI, false); +} + +CPDF_BAFontMap::~CPDF_BAFontMap() = default; + +RetainPtr<CPDF_Font> CPDF_BAFontMap::GetPDFFont(int32_t nFontIndex) { + if (fxcrt::IndexInBounds(m_Data, nFontIndex)) + return m_Data[nFontIndex]->pFont; + return nullptr; +} + +ByteString CPDF_BAFontMap::GetPDFFontAlias(int32_t nFontIndex) { + if (fxcrt::IndexInBounds(m_Data, nFontIndex)) + return m_Data[nFontIndex]->sFontName; + return ByteString(); +} + +int32_t CPDF_BAFontMap::GetWordFontIndex(uint16_t word, + FX_Charset nCharset, + int32_t nFontIndex) { + if (nFontIndex > 0) { + if (KnowWord(nFontIndex, word)) + return nFontIndex; + } else { + if (!m_Data.empty()) { + const Data* pData = m_Data.front().get(); + if (nCharset == FX_Charset::kDefault || + pData->nCharset == FX_Charset::kSymbol || + nCharset == pData->nCharset) { + if (KnowWord(0, word)) + return 0; + } + } + } + + int32_t nNewFontIndex = + GetFontIndex(GetCachedNativeFontName(nCharset), nCharset, true); + if (nNewFontIndex >= 0) { + if (KnowWord(nNewFontIndex, word)) + return nNewFontIndex; + } + nNewFontIndex = GetFontIndex(CFX_Font::kUniversalDefaultFontName, + FX_Charset::kDefault, false); + if (nNewFontIndex >= 0) { + if (KnowWord(nNewFontIndex, word)) + return nNewFontIndex; + } + return -1; +} + +int32_t CPDF_BAFontMap::CharCodeFromUnicode(int32_t nFontIndex, uint16_t word) { + if (!fxcrt::IndexInBounds(m_Data, nFontIndex)) + return -1; + + Data* pData = m_Data[nFontIndex].get(); + if (!pData->pFont) + return -1; + + if (pData->pFont->IsUnicodeCompatible()) + return pData->pFont->CharCodeFromUnicode(word); + + return word < 0xFF ? word : -1; +} + +FX_Charset CPDF_BAFontMap::CharSetFromUnicode(uint16_t word, + FX_Charset nOldCharset) { + // to avoid CJK Font to show ASCII + if (word < 0x7F) + return FX_Charset::kANSI; + + // follow the old charset + if (nOldCharset != FX_Charset::kDefault) + return nOldCharset; + + return CFX_Font::GetCharSetFromUnicode(word); +} + +FX_Charset CPDF_BAFontMap::GetNativeCharset() { + return FX_GetCharsetFromCodePage(FX_GetACP()); +} + +RetainPtr<CPDF_Font> CPDF_BAFontMap::FindFontSameCharset(ByteString* sFontAlias, + FX_Charset nCharset) { + if (m_pAnnotDict->GetNameFor(pdfium::annotation::kSubtype) != "Widget") + return nullptr; + + const CPDF_Dictionary* pRootDict = m_pDocument->GetRoot(); + if (!pRootDict) + return nullptr; + + RetainPtr<const CPDF_Dictionary> pAcroFormDict = + pRootDict->GetDictFor("AcroForm"); + if (!pAcroFormDict) + return nullptr; + + RetainPtr<const CPDF_Dictionary> pDRDict = pAcroFormDict->GetDictFor("DR"); + if (!pDRDict) + return nullptr; + + return FindResFontSameCharset(pDRDict.Get(), sFontAlias, nCharset); +} + +RetainPtr<CPDF_Font> CPDF_BAFontMap::FindResFontSameCharset( + const CPDF_Dictionary* pResDict, + ByteString* sFontAlias, + FX_Charset nCharset) { + if (!pResDict) + return nullptr; + + RetainPtr<const CPDF_Dictionary> pFonts = pResDict->GetDictFor("Font"); + if (!pFonts) + return nullptr; + + RetainPtr<CPDF_Font> pFind; + CPDF_DictionaryLocker locker(pFonts); + for (const auto& it : locker) { + const ByteString& csKey = it.first; + RetainPtr<CPDF_Dictionary> pElement = + ToDictionary(it.second->GetMutableDirect()); + if (!ValidateDictType(pElement.Get(), "Font")) + continue; + + auto* pData = CPDF_DocPageData::FromDocument(m_pDocument); + RetainPtr<CPDF_Font> pFont = pData->GetFont(std::move(pElement)); + if (!pFont) + continue; + + auto maybe_charset = pFont->GetSubstFontCharset(); + if (maybe_charset.has_value() && maybe_charset.value() == nCharset) { + *sFontAlias = csKey; + pFind = std::move(pFont); + } + } + return pFind; +} + +RetainPtr<CPDF_Font> CPDF_BAFontMap::GetAnnotDefaultFont(ByteString* sAlias) { + RetainPtr<CPDF_Dictionary> pAcroFormDict; + const bool bWidget = + (m_pAnnotDict->GetNameFor(pdfium::annotation::kSubtype) == "Widget"); + if (bWidget) { + RetainPtr<CPDF_Dictionary> pRootDict = m_pDocument->GetMutableRoot(); + if (pRootDict) + pAcroFormDict = pRootDict->GetMutableDictFor("AcroForm"); + } + + ByteString sDA; + RetainPtr<const CPDF_Object> pObj = + CPDF_FormField::GetFieldAttrForDict(m_pAnnotDict.Get(), "DA"); + if (pObj) + sDA = pObj->GetString(); + + if (bWidget) { + if (sDA.IsEmpty()) { + pObj = CPDF_FormField::GetFieldAttrForDict(pAcroFormDict.Get(), "DA"); + sDA = pObj ? pObj->GetString() : ByteString(); + } + } + if (sDA.IsEmpty()) + return nullptr; + + CPDF_DefaultAppearance appearance(sDA); + float font_size; + absl::optional<ByteString> font = appearance.GetFont(&font_size); + *sAlias = font.value_or(ByteString()); + + RetainPtr<CPDF_Dictionary> pFontDict; + if (RetainPtr<CPDF_Dictionary> pAPDict = + m_pAnnotDict->GetMutableDictFor(pdfium::annotation::kAP)) { + if (RetainPtr<CPDF_Dictionary> pNormalDict = + pAPDict->GetMutableDictFor("N")) { + if (RetainPtr<CPDF_Dictionary> pNormalResDict = + pNormalDict->GetMutableDictFor("Resources")) { + if (RetainPtr<CPDF_Dictionary> pResFontDict = + pNormalResDict->GetMutableDictFor("Font")) { + pFontDict = pResFontDict->GetMutableDictFor(*sAlias); + } + } + } + } + if (bWidget && !pFontDict && pAcroFormDict) { + if (RetainPtr<CPDF_Dictionary> pDRDict = + pAcroFormDict->GetMutableDictFor("DR")) { + if (RetainPtr<CPDF_Dictionary> pDRFontDict = + pDRDict->GetMutableDictFor("Font")) { + pFontDict = pDRFontDict->GetMutableDictFor(*sAlias); + } + } + } + if (!pFontDict) + return nullptr; + + return CPDF_DocPageData::FromDocument(m_pDocument)->GetFont(pFontDict); +} + +void CPDF_BAFontMap::AddFontToAnnotDict(const RetainPtr<CPDF_Font>& pFont, + const ByteString& sAlias) { + if (!pFont) + return; + + RetainPtr<CPDF_Dictionary> pAPDict = + m_pAnnotDict->GetOrCreateDictFor(pdfium::annotation::kAP); + + // to avoid checkbox and radiobutton + if (ToDictionary(pAPDict->GetObjectFor(m_sAPType))) + return; + + RetainPtr<CPDF_Stream> pStream = pAPDict->GetMutableStreamFor(m_sAPType); + if (!pStream) { + pStream = m_pDocument->NewIndirect<CPDF_Stream>(); + pAPDict->SetNewFor<CPDF_Reference>(m_sAPType, m_pDocument, + pStream->GetObjNum()); + } + + RetainPtr<CPDF_Dictionary> pStreamDict = pStream->GetMutableDict(); + if (!pStreamDict) { + pStreamDict = m_pDocument->New<CPDF_Dictionary>(); + pStream->InitStreamWithEmptyData(pStreamDict); + } + + RetainPtr<CPDF_Dictionary> pStreamResList = + pStreamDict->GetOrCreateDictFor("Resources"); + RetainPtr<CPDF_Dictionary> pStreamResFontList = + pStreamResList->GetMutableDictFor("Font"); + if (!pStreamResFontList) { + pStreamResFontList = m_pDocument->NewIndirect<CPDF_Dictionary>(); + pStreamResList->SetNewFor<CPDF_Reference>("Font", m_pDocument, + pStreamResFontList->GetObjNum()); + } + if (!pStreamResFontList->KeyExist(sAlias)) { + RetainPtr<const CPDF_Dictionary> pFontDict = pFont->GetFontDict(); + RetainPtr<CPDF_Object> pObject = + pFontDict->IsInline() ? pFontDict->Clone() + : pFontDict->MakeReference(m_pDocument); + pStreamResFontList->SetFor(sAlias, std::move(pObject)); + } +} + +bool CPDF_BAFontMap::KnowWord(int32_t nFontIndex, uint16_t word) { + return fxcrt::IndexInBounds(m_Data, nFontIndex) && + CharCodeFromUnicode(nFontIndex, word) >= 0; +} + +int32_t CPDF_BAFontMap::GetFontIndex(const ByteString& sFontName, + FX_Charset nCharset, + bool bFind) { + int32_t nFontIndex = FindFont(EncodeFontAlias(sFontName, nCharset), nCharset); + if (nFontIndex >= 0) + return nFontIndex; + + ByteString sAlias; + RetainPtr<CPDF_Font> pFont = + bFind ? FindFontSameCharset(&sAlias, nCharset) : nullptr; + if (!pFont) { + pFont = AddFontToDocument(sFontName, nCharset); + sAlias = EncodeFontAlias(sFontName, nCharset); + } + AddFontToAnnotDict(pFont, sAlias); + return AddFontData(pFont, sAlias, nCharset); +} + +int32_t CPDF_BAFontMap::AddFontData(const RetainPtr<CPDF_Font>& pFont, + const ByteString& sFontAlias, + FX_Charset nCharset) { + auto pNewData = std::make_unique<Data>(); + pNewData->pFont = pFont; + pNewData->sFontName = sFontAlias; + pNewData->nCharset = nCharset; + m_Data.push_back(std::move(pNewData)); + return fxcrt::CollectionSize<int32_t>(m_Data) - 1; +} + +int32_t CPDF_BAFontMap::FindFont(const ByteString& sFontName, + FX_Charset nCharset) { + int32_t i = 0; + for (const auto& pData : m_Data) { + if ((nCharset == FX_Charset::kDefault || nCharset == pData->nCharset) && + (sFontName.IsEmpty() || pData->sFontName == sFontName)) { + return i; + } + ++i; + } + return -1; +} + +ByteString CPDF_BAFontMap::GetNativeFontName(FX_Charset nCharset) { + if (nCharset == FX_Charset::kDefault) + nCharset = GetNativeCharset(); + + ByteString sFontName = CFX_Font::GetDefaultFontNameByCharset(nCharset); + if (!FindNativeTrueTypeFont(sFontName.AsStringView())) + return ByteString(); + + return sFontName; +} + +ByteString CPDF_BAFontMap::GetCachedNativeFontName(FX_Charset nCharset) { + for (const auto& pData : m_NativeFont) { + if (pData && pData->nCharset == nCharset) + return pData->sFontName; + } + + ByteString sNew = GetNativeFontName(nCharset); + if (sNew.IsEmpty()) + return ByteString(); + + auto pNewData = std::make_unique<Native>(); + pNewData->nCharset = nCharset; + pNewData->sFontName = sNew; + m_NativeFont.push_back(std::move(pNewData)); + return sNew; +} + +RetainPtr<CPDF_Font> CPDF_BAFontMap::AddFontToDocument(ByteString sFontName, + FX_Charset nCharset) { + if (CFX_FontMapper::IsStandardFontName(sFontName)) + return AddStandardFont(sFontName); + + return AddSystemFont(sFontName, nCharset); +} + +RetainPtr<CPDF_Font> CPDF_BAFontMap::AddStandardFont(ByteString sFontName) { + auto* pPageData = CPDF_DocPageData::FromDocument(m_pDocument); + if (sFontName == "ZapfDingbats") + return pPageData->AddStandardFont(sFontName, nullptr); + + static const CPDF_FontEncoding fe(FontEncoding::kWinAnsi); + return pPageData->AddStandardFont(sFontName, &fe); +} + +RetainPtr<CPDF_Font> CPDF_BAFontMap::AddSystemFont(ByteString sFontName, + FX_Charset nCharset) { + if (sFontName.IsEmpty()) + sFontName = GetNativeFontName(nCharset); + + if (nCharset == FX_Charset::kDefault) + nCharset = GetNativeCharset(); + + return AddNativeTrueTypeFontToPDF(m_pDocument, sFontName, nCharset); +}
diff --git a/core/fpdfdoc/cpdf_bafontmap.h b/core/fpdfdoc/cpdf_bafontmap.h new file mode 100644 index 0000000..5cd4bcd --- /dev/null +++ b/core/fpdfdoc/cpdf_bafontmap.h
@@ -0,0 +1,89 @@ +// Copyright 2014 The PDFium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com + +#ifndef CORE_FPDFDOC_CPDF_BAFONTMAP_H_ +#define CORE_FPDFDOC_CPDF_BAFONTMAP_H_ + +#include <memory> +#include <vector> + +#include "core/fpdfdoc/ipvt_fontmap.h" +#include "core/fxcrt/fx_codepage.h" +#include "core/fxcrt/retain_ptr.h" +#include "core/fxcrt/unowned_ptr.h" + +class CPDF_Dictionary; +class CPDF_Document; + +class CPDF_BAFontMap final : public IPVT_FontMap { + public: + static FX_Charset GetNativeCharset(); + + CPDF_BAFontMap(CPDF_Document* pDocument, + RetainPtr<CPDF_Dictionary> pAnnotDict, + const ByteString& sAPType); + ~CPDF_BAFontMap() override; + + // IPVT_FontMap: + RetainPtr<CPDF_Font> GetPDFFont(int32_t nFontIndex) override; + ByteString GetPDFFontAlias(int32_t nFontIndex) override; + int32_t GetWordFontIndex(uint16_t word, + FX_Charset nCharset, + int32_t nFontIndex) override; + int32_t CharCodeFromUnicode(int32_t nFontIndex, uint16_t word) override; + FX_Charset CharSetFromUnicode(uint16_t word, FX_Charset nOldCharset) override; + + private: + struct Data { + Data(); + ~Data(); + + FX_Charset nCharset = FX_Charset::kANSI; + RetainPtr<CPDF_Font> pFont; + ByteString sFontName; + }; + + struct Native { + FX_Charset nCharset; + ByteString sFontName; + }; + + RetainPtr<CPDF_Font> FindFontSameCharset(ByteString* sFontAlias, + FX_Charset nCharset); + RetainPtr<CPDF_Font> FindResFontSameCharset(const CPDF_Dictionary* pResDict, + ByteString* sFontAlias, + FX_Charset nCharset); + RetainPtr<CPDF_Font> GetAnnotDefaultFont(ByteString* sAlias); + void AddFontToAnnotDict(const RetainPtr<CPDF_Font>& pFont, + const ByteString& sAlias); + + bool KnowWord(int32_t nFontIndex, uint16_t word); + + int32_t GetFontIndex(const ByteString& sFontName, + FX_Charset nCharset, + bool bFind); + int32_t AddFontData(const RetainPtr<CPDF_Font>& pFont, + const ByteString& sFontAlias, + FX_Charset nCharset); + + int32_t FindFont(const ByteString& sFontName, FX_Charset nCharset); + ByteString GetNativeFontName(FX_Charset nCharset); + ByteString GetCachedNativeFontName(FX_Charset nCharset); + RetainPtr<CPDF_Font> AddFontToDocument(ByteString sFontName, + FX_Charset nCharset); + RetainPtr<CPDF_Font> AddStandardFont(ByteString sFontName); + RetainPtr<CPDF_Font> AddSystemFont(ByteString sFontName, FX_Charset nCharset); + + std::vector<std::unique_ptr<Data>> m_Data; + std::vector<std::unique_ptr<Native>> m_NativeFont; + UnownedPtr<CPDF_Document> const m_pDocument; + RetainPtr<CPDF_Dictionary> const m_pAnnotDict; + RetainPtr<CPDF_Font> m_pDefaultFont; + ByteString m_sDefaultFontName; + const ByteString m_sAPType; +}; + +#endif // CORE_FPDFDOC_CPDF_BAFONTMAP_H_
diff --git a/core/fpdfdoc/cpdf_bafontmap_unittest.cpp b/core/fpdfdoc/cpdf_bafontmap_unittest.cpp new file mode 100644 index 0000000..25e7da5 --- /dev/null +++ b/core/fpdfdoc/cpdf_bafontmap_unittest.cpp
@@ -0,0 +1,63 @@ +// Copyright 2022 The PDFium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "core/fpdfdoc/cpdf_bafontmap.h" + +#include <utility> + +#include "build/build_config.h" +#include "constants/annotation_common.h" +#include "core/fpdfapi/font/cpdf_font.h" +#include "core/fpdfapi/page/test_with_page_module.h" +#include "core/fpdfapi/parser/cpdf_dictionary.h" +#include "core/fpdfapi/parser/cpdf_name.h" +#include "core/fpdfapi/parser/cpdf_string.h" +#include "core/fpdfapi/parser/cpdf_test_document.h" + +using BAFontMapTest = TestWithPageModule; + +TEST_F(BAFontMapTest, DefaultFont) { + // Without any font resources, CPDF_BAFontMap generates a default font. + CPDF_TestDocument doc; + + auto annot_dict = pdfium::MakeRetain<CPDF_Dictionary>(); + annot_dict->SetNewFor<CPDF_Name>(pdfium::annotation::kSubtype, "Widget"); + annot_dict->SetNewFor<CPDF_String>("DA", "0 0 0 rg /F1 12 Tf", + /*bHex=*/false); + + CPDF_BAFontMap font_map(&doc, std::move(annot_dict), "N"); +#if !BUILDFLAG(IS_WIN) + // TODO(thestig): Figure out why this does not work on Windows. + EXPECT_EQ(font_map.GetPDFFontAlias(0), "Helvetica_00"); +#endif + RetainPtr<CPDF_Font> font = font_map.GetPDFFont(0); + ASSERT_TRUE(font); + EXPECT_TRUE(font->IsType1Font()); + EXPECT_EQ(font->GetBaseFontName(), "Helvetica"); +} + +TEST_F(BAFontMapTest, Bug853238) { + CPDF_TestDocument doc; + auto root_dict = pdfium::MakeRetain<CPDF_Dictionary>(); + auto acroform_dict = root_dict->SetNewFor<CPDF_Dictionary>("AcroForm"); + auto annot_dr_dict = acroform_dict->SetNewFor<CPDF_Dictionary>("DR"); + auto annot_font_dict = annot_dr_dict->SetNewFor<CPDF_Dictionary>("Font"); + auto annot_font_f1_dict = annot_font_dict->SetNewFor<CPDF_Dictionary>("F1"); + annot_font_f1_dict->SetNewFor<CPDF_Name>("Type", "Font"); + annot_font_f1_dict->SetNewFor<CPDF_Name>("Subtype", "Type1"); + annot_font_f1_dict->SetNewFor<CPDF_Name>("BaseFont", "Times-Roman"); + doc.SetRoot(root_dict); + + auto annot_dict = pdfium::MakeRetain<CPDF_Dictionary>(); + annot_dict->SetNewFor<CPDF_Name>(pdfium::annotation::kSubtype, "Widget"); + annot_dict->SetNewFor<CPDF_String>("DA", "0 0 0 rg /F1 12 Tf", + /*bHex=*/false); + + CPDF_BAFontMap font_map(&doc, std::move(annot_dict), "N"); + EXPECT_EQ(font_map.GetPDFFontAlias(0), "F1"); + RetainPtr<CPDF_Font> font = font_map.GetPDFFont(0); + ASSERT_TRUE(font); + EXPECT_TRUE(font->IsType1Font()); + EXPECT_EQ(font->GetBaseFontName(), "Times-Roman"); +}
diff --git a/core/fpdfdoc/cpdf_bookmark.cpp b/core/fpdfdoc/cpdf_bookmark.cpp index b08fba5..f4176b9 100644 --- a/core/fpdfdoc/cpdf_bookmark.cpp +++ b/core/fpdfdoc/cpdf_bookmark.cpp
@@ -1,4 +1,4 @@ -// Copyright 2016 PDFium Authors. All rights reserved. +// Copyright 2016 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -6,21 +6,20 @@ #include "core/fpdfdoc/cpdf_bookmark.h" -#include <memory> -#include <vector> +#include <utility> #include "core/fpdfapi/parser/cpdf_array.h" #include "core/fpdfapi/parser/cpdf_dictionary.h" #include "core/fpdfapi/parser/cpdf_string.h" -#include "core/fpdfdoc/cpdf_nametree.h" -#include "core/fxcrt/fx_memory_wrappers.h" -#include "core/fxge/fx_dib.h" +#include "core/fxcrt/data_vector.h" +#include "core/fxge/dib/fx_dib.h" CPDF_Bookmark::CPDF_Bookmark() = default; CPDF_Bookmark::CPDF_Bookmark(const CPDF_Bookmark& that) = default; -CPDF_Bookmark::CPDF_Bookmark(const CPDF_Dictionary* pDict) : m_pDict(pDict) {} +CPDF_Bookmark::CPDF_Bookmark(RetainPtr<const CPDF_Dictionary> pDict) + : m_pDict(std::move(pDict)) {} CPDF_Bookmark::~CPDF_Bookmark() = default; @@ -28,17 +27,18 @@ if (!m_pDict) return WideString(); - const CPDF_String* pString = ToString(m_pDict->GetDirectObjectFor("Title")); + RetainPtr<const CPDF_String> pString = + ToString(m_pDict->GetDirectObjectFor("Title")); if (!pString) return WideString(); WideString title = pString->GetUnicodeText(); - int len = title.GetLength(); + size_t len = title.GetLength(); if (!len) return WideString(); - std::vector<wchar_t, FxAllocAllocator<wchar_t>> buf(len); - for (int i = 0; i < len; i++) { + DataVector<wchar_t> buf(len); + for (size_t i = 0; i < len; i++) { wchar_t w = title[i]; buf[i] = w > 0x20 ? w : 0x20; } @@ -47,21 +47,14 @@ CPDF_Dest CPDF_Bookmark::GetDest(CPDF_Document* pDocument) const { if (!m_pDict) - return CPDF_Dest(); - - const CPDF_Object* pDest = m_pDict->GetDirectObjectFor("Dest"); - if (!pDest) - return CPDF_Dest(); - if (pDest->IsString() || pDest->IsName()) { - CPDF_NameTree name_tree(pDocument, "Dests"); - return CPDF_Dest( - name_tree.LookupNamedDest(pDocument, pDest->GetUnicodeText())); - } - if (const CPDF_Array* pArray = pDest->AsArray()) - return CPDF_Dest(pArray); - return CPDF_Dest(); + return CPDF_Dest(nullptr); + return CPDF_Dest::Create(pDocument, m_pDict->GetDirectObjectFor("Dest")); } CPDF_Action CPDF_Bookmark::GetAction() const { return CPDF_Action(m_pDict ? m_pDict->GetDictFor("A") : nullptr); } + +int CPDF_Bookmark::GetCount() const { + return m_pDict->GetIntegerFor("Count"); +}
diff --git a/core/fpdfdoc/cpdf_bookmark.h b/core/fpdfdoc/cpdf_bookmark.h index b185c03..11a9d18 100644 --- a/core/fpdfdoc/cpdf_bookmark.h +++ b/core/fpdfdoc/cpdf_bookmark.h
@@ -1,4 +1,4 @@ -// Copyright 2016 PDFium Authors. All rights reserved. +// Copyright 2016 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -9,8 +9,8 @@ #include "core/fpdfdoc/cpdf_action.h" #include "core/fpdfdoc/cpdf_dest.h" -#include "core/fxcrt/fx_string.h" #include "core/fxcrt/retain_ptr.h" +#include "core/fxcrt/widestring.h" class CPDF_Dictionary; class CPDF_Document; @@ -19,7 +19,7 @@ public: CPDF_Bookmark(); CPDF_Bookmark(const CPDF_Bookmark& that); - explicit CPDF_Bookmark(const CPDF_Dictionary* pDict); + explicit CPDF_Bookmark(RetainPtr<const CPDF_Dictionary> pDict); ~CPDF_Bookmark(); const CPDF_Dictionary* GetDict() const { return m_pDict.Get(); } @@ -27,6 +27,7 @@ WideString GetTitle() const; CPDF_Dest GetDest(CPDF_Document* pDocument) const; CPDF_Action GetAction() const; + int GetCount() const; private: RetainPtr<const CPDF_Dictionary> m_pDict;
diff --git a/core/fpdfdoc/cpdf_bookmarktree.cpp b/core/fpdfdoc/cpdf_bookmarktree.cpp index 5c4fffe..1f1aea9 100644 --- a/core/fpdfdoc/cpdf_bookmarktree.cpp +++ b/core/fpdfdoc/cpdf_bookmarktree.cpp
@@ -1,4 +1,4 @@ -// Copyright 2016 PDFium Authors. All rights reserved. +// Copyright 2016 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -6,32 +6,37 @@ #include "core/fpdfdoc/cpdf_bookmarktree.h" +#include <utility> + #include "core/fpdfapi/parser/cpdf_dictionary.h" #include "core/fpdfapi/parser/cpdf_document.h" -CPDF_BookmarkTree::CPDF_BookmarkTree(CPDF_Document* pDoc) : m_pDocument(pDoc) {} +CPDF_BookmarkTree::CPDF_BookmarkTree(const CPDF_Document* doc) + : document_(doc) {} CPDF_BookmarkTree::~CPDF_BookmarkTree() = default; -CPDF_Bookmark CPDF_BookmarkTree::GetFirstChild(CPDF_Bookmark* parent) const { - const CPDF_Dictionary* pParentDict = parent->GetDict(); - if (pParentDict) - return CPDF_Bookmark(pParentDict->GetDictFor("First")); +CPDF_Bookmark CPDF_BookmarkTree::GetFirstChild( + const CPDF_Bookmark& parent) const { + const CPDF_Dictionary* parent_dict = parent.GetDict(); + if (parent_dict) + return CPDF_Bookmark(parent_dict->GetDictFor("First")); - CPDF_Dictionary* pRoot = m_pDocument->GetRoot(); - if (!pRoot) + const CPDF_Dictionary* root = document_->GetRoot(); + if (!root) return CPDF_Bookmark(); - CPDF_Dictionary* pOutlines = pRoot->GetDictFor("Outlines"); - return pOutlines ? CPDF_Bookmark(pOutlines->GetDictFor("First")) - : CPDF_Bookmark(); + RetainPtr<const CPDF_Dictionary> outlines = root->GetDictFor("Outlines"); + return outlines ? CPDF_Bookmark(outlines->GetDictFor("First")) + : CPDF_Bookmark(); } -CPDF_Bookmark CPDF_BookmarkTree::GetNextSibling(CPDF_Bookmark* bookmark) const { - const CPDF_Dictionary* pDict = bookmark->GetDict(); - if (!pDict) +CPDF_Bookmark CPDF_BookmarkTree::GetNextSibling( + const CPDF_Bookmark& bookmark) const { + const CPDF_Dictionary* dict = bookmark.GetDict(); + if (!dict) return CPDF_Bookmark(); - const CPDF_Dictionary* pNext = pDict->GetDictFor("Next"); - return pNext == pDict ? CPDF_Bookmark() : CPDF_Bookmark(pNext); + RetainPtr<const CPDF_Dictionary> next = dict->GetDictFor("Next"); + return next != dict ? CPDF_Bookmark(std::move(next)) : CPDF_Bookmark(); }
diff --git a/core/fpdfdoc/cpdf_bookmarktree.h b/core/fpdfdoc/cpdf_bookmarktree.h index b374bfa..144879b 100644 --- a/core/fpdfdoc/cpdf_bookmarktree.h +++ b/core/fpdfdoc/cpdf_bookmarktree.h
@@ -1,4 +1,4 @@ -// Copyright 2016 PDFium Authors. All rights reserved. +// Copyright 2016 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -14,15 +14,14 @@ class CPDF_BookmarkTree { public: - explicit CPDF_BookmarkTree(CPDF_Document* pDoc); + explicit CPDF_BookmarkTree(const CPDF_Document* doc); ~CPDF_BookmarkTree(); - CPDF_Bookmark GetFirstChild(CPDF_Bookmark* parent) const; - CPDF_Bookmark GetNextSibling(CPDF_Bookmark* bookmark) const; - CPDF_Document* GetDocument() const { return m_pDocument.Get(); } + CPDF_Bookmark GetFirstChild(const CPDF_Bookmark& parent) const; + CPDF_Bookmark GetNextSibling(const CPDF_Bookmark& bookmark) const; private: - UnownedPtr<CPDF_Document> const m_pDocument; + UnownedPtr<const CPDF_Document> const document_; }; #endif // CORE_FPDFDOC_CPDF_BOOKMARKTREE_H_
diff --git a/core/fpdfdoc/cpdf_color_utils.cpp b/core/fpdfdoc/cpdf_color_utils.cpp index 198b1ca..b4e1d86 100644 --- a/core/fpdfdoc/cpdf_color_utils.cpp +++ b/core/fpdfdoc/cpdf_color_utils.cpp
@@ -1,4 +1,4 @@ -// Copyright 2019 PDFium Authors. All rights reserved. +// Copyright 2019 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -9,6 +9,7 @@ #include "core/fpdfapi/parser/cpdf_array.h" #include "core/fpdfdoc/cpdf_defaultappearance.h" #include "core/fxcrt/bytestring.h" +#include "third_party/base/notreached.h" namespace fpdfdoc { @@ -16,16 +17,16 @@ CFX_Color rt; switch (array.size()) { case 1: - rt = CFX_Color(CFX_Color::kGray, array.GetNumberAt(0)); + rt = CFX_Color(CFX_Color::Type::kGray, array.GetFloatAt(0)); break; case 3: - rt = CFX_Color(CFX_Color::kRGB, array.GetNumberAt(0), - array.GetNumberAt(1), array.GetNumberAt(2)); + rt = CFX_Color(CFX_Color::Type::kRGB, array.GetFloatAt(0), + array.GetFloatAt(1), array.GetFloatAt(2)); break; case 4: - rt = CFX_Color(CFX_Color::kCMYK, array.GetNumberAt(0), - array.GetNumberAt(1), array.GetNumberAt(2), - array.GetNumberAt(3)); + rt = CFX_Color(CFX_Color::Type::kCMYK, array.GetFloatAt(0), + array.GetFloatAt(1), array.GetFloatAt(2), + array.GetFloatAt(3)); break; } return rt; @@ -33,21 +34,7 @@ CFX_Color CFXColorFromString(const ByteString& str) { CPDF_DefaultAppearance appearance(str); - float values[4]; - Optional<CFX_Color::Type> color_type = appearance.GetColor(values); - if (!color_type || *color_type == CFX_Color::kTransparent) - return CFX_Color(CFX_Color::kTransparent); - if (*color_type == CFX_Color::kGray) - return CFX_Color(CFX_Color::kGray, values[0]); - if (*color_type == CFX_Color::kRGB) - return CFX_Color(CFX_Color::kRGB, values[0], values[1], values[2]); - if (*color_type == CFX_Color::kCMYK) { - return CFX_Color(CFX_Color::kCMYK, values[0], values[1], values[2], - values[3]); - } - - NOTREACHED(); - return CFX_Color(CFX_Color::kTransparent); + return appearance.GetColor().value_or(CFX_Color()); } } // namespace fpdfdoc
diff --git a/core/fpdfdoc/cpdf_color_utils.h b/core/fpdfdoc/cpdf_color_utils.h index 993a7d7..05998cb 100644 --- a/core/fpdfdoc/cpdf_color_utils.h +++ b/core/fpdfdoc/cpdf_color_utils.h
@@ -1,4 +1,4 @@ -// Copyright 2019 PDFium Authors. All rights reserved. +// Copyright 2019 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file.
diff --git a/core/fpdfdoc/cpdf_defaultappearance.cpp b/core/fpdfdoc/cpdf_defaultappearance.cpp index e6ef4f7..1eda1d9 100644 --- a/core/fpdfdoc/cpdf_defaultappearance.cpp +++ b/core/fpdfdoc/cpdf_defaultappearance.cpp
@@ -1,4 +1,4 @@ -// Copyright 2016 PDFium Authors. All rights reserved. +// Copyright 2016 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -11,7 +11,9 @@ #include "core/fpdfapi/parser/cpdf_simple_parser.h" #include "core/fpdfapi/parser/fpdf_parser_utility.h" +#include "core/fxcrt/fx_string.h" #include "core/fxge/cfx_color.h" +#include "third_party/base/notreached.h" namespace { @@ -27,7 +29,7 @@ int buf_count = 0; parser->SetCurPos(0); - while (1) { + while (true) { pBuf[buf_index++] = parser->GetCurPos(); if (buf_index == nParams) buf_index = 0; @@ -48,15 +50,25 @@ return true; } } - return false; } } // namespace -Optional<ByteString> CPDF_DefaultAppearance::GetFont(float* fFontSize) { +CPDF_DefaultAppearance::CPDF_DefaultAppearance() = default; + +CPDF_DefaultAppearance::CPDF_DefaultAppearance(const ByteString& csDA) + : m_csDA(csDA) {} + +CPDF_DefaultAppearance::CPDF_DefaultAppearance( + const CPDF_DefaultAppearance& cDA) = default; + +CPDF_DefaultAppearance::~CPDF_DefaultAppearance() = default; + +absl::optional<ByteString> CPDF_DefaultAppearance::GetFont( + float* fFontSize) const { *fFontSize = 0.0f; if (m_csDA.IsEmpty()) - return {}; + return absl::nullopt; ByteString csFontNameTag; CPDF_SimpleParser syntax(m_csDA.AsStringView().raw_span()); @@ -65,67 +77,69 @@ csFontNameTag.Delete(0, 1); *fFontSize = StringToFloat(syntax.GetWord()); } - return {PDF_NameDecode(csFontNameTag.AsStringView())}; + return PDF_NameDecode(csFontNameTag.AsStringView()); } -Optional<CFX_Color::Type> CPDF_DefaultAppearance::GetColor(float fc[4]) { - for (int c = 0; c < 4; c++) - fc[c] = 0; - +absl::optional<CFX_Color> CPDF_DefaultAppearance::GetColor() const { if (m_csDA.IsEmpty()) - return {}; + return absl::nullopt; + float fc[4]; CPDF_SimpleParser syntax(m_csDA.AsStringView().raw_span()); if (FindTagParamFromStart(&syntax, "g", 1)) { fc[0] = StringToFloat(syntax.GetWord()); - return {CFX_Color::kGray}; + return CFX_Color(CFX_Color::Type::kGray, fc[0]); } if (FindTagParamFromStart(&syntax, "rg", 3)) { fc[0] = StringToFloat(syntax.GetWord()); fc[1] = StringToFloat(syntax.GetWord()); fc[2] = StringToFloat(syntax.GetWord()); - return {CFX_Color::kRGB}; + return CFX_Color(CFX_Color::Type::kRGB, fc[0], fc[1], fc[2]); } if (FindTagParamFromStart(&syntax, "k", 4)) { fc[0] = StringToFloat(syntax.GetWord()); fc[1] = StringToFloat(syntax.GetWord()); fc[2] = StringToFloat(syntax.GetWord()); fc[3] = StringToFloat(syntax.GetWord()); - return {CFX_Color::kCMYK}; + return CFX_Color(CFX_Color::Type::kCMYK, fc[0], fc[1], fc[2], fc[3]); } - - return {}; + return absl::nullopt; } -std::pair<Optional<CFX_Color::Type>, FX_ARGB> -CPDF_DefaultAppearance::GetColor() { - float values[4]; - Optional<CFX_Color::Type> type = GetColor(values); - if (!type) - return {type, 0}; +absl::optional<CFX_Color::TypeAndARGB> CPDF_DefaultAppearance::GetColorARGB() + const { + absl::optional<CFX_Color> maybe_color = GetColor(); + if (!maybe_color.has_value()) + return absl::nullopt; - if (*type == CFX_Color::kGray) { - int g = static_cast<int>(values[0] * 255 + 0.5f); - return {type, ArgbEncode(255, g, g, g)}; + const CFX_Color& color = maybe_color.value(); + if (color.nColorType == CFX_Color::Type::kGray) { + int g = static_cast<int>(color.fColor1 * 255 + 0.5f); + return CFX_Color::TypeAndARGB(CFX_Color::Type::kGray, + ArgbEncode(255, g, g, g)); } - if (*type == CFX_Color::kRGB) { - int r = static_cast<int>(values[0] * 255 + 0.5f); - int g = static_cast<int>(values[1] * 255 + 0.5f); - int b = static_cast<int>(values[2] * 255 + 0.5f); - return {type, ArgbEncode(255, r, g, b)}; + if (color.nColorType == CFX_Color::Type::kRGB) { + int r = static_cast<int>(color.fColor1 * 255 + 0.5f); + int g = static_cast<int>(color.fColor2 * 255 + 0.5f); + int b = static_cast<int>(color.fColor3 * 255 + 0.5f); + return CFX_Color::TypeAndARGB(CFX_Color::Type::kRGB, + ArgbEncode(255, r, g, b)); } - if (*type == CFX_Color::kCMYK) { - float r = 1.0f - std::min(1.0f, values[0] + values[3]); - float g = 1.0f - std::min(1.0f, values[1] + values[3]); - float b = 1.0f - std::min(1.0f, values[2] + values[3]); - return {type, ArgbEncode(255, static_cast<int>(r * 255 + 0.5f), - static_cast<int>(g * 255 + 0.5f), - static_cast<int>(b * 255 + 0.5f))}; + if (color.nColorType == CFX_Color::Type::kCMYK) { + float r = 1.0f - std::min(1.0f, color.fColor1 + color.fColor4); + float g = 1.0f - std::min(1.0f, color.fColor2 + color.fColor4); + float b = 1.0f - std::min(1.0f, color.fColor3 + color.fColor4); + return CFX_Color::TypeAndARGB( + CFX_Color::Type::kCMYK, + ArgbEncode(255, static_cast<int>(r * 255 + 0.5f), + static_cast<int>(g * 255 + 0.5f), + static_cast<int>(b * 255 + 0.5f))); } NOTREACHED(); - return {{}, 0}; + return absl::nullopt; } +// static bool CPDF_DefaultAppearance::FindTagParamFromStartForTesting( CPDF_SimpleParser* parser, ByteStringView token,
diff --git a/core/fpdfdoc/cpdf_defaultappearance.h b/core/fpdfdoc/cpdf_defaultappearance.h index 97762f8..42389ec 100644 --- a/core/fpdfdoc/cpdf_defaultappearance.h +++ b/core/fpdfdoc/cpdf_defaultappearance.h
@@ -1,4 +1,4 @@ -// Copyright 2016 PDFium Authors. All rights reserved. +// Copyright 2016 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -7,32 +7,30 @@ #ifndef CORE_FPDFDOC_CPDF_DEFAULTAPPEARANCE_H_ #define CORE_FPDFDOC_CPDF_DEFAULTAPPEARANCE_H_ -#include <utility> - -#include "core/fpdfapi/parser/cpdf_simple_parser.h" -#include "core/fxcrt/fx_string.h" -#include "core/fxcrt/fx_system.h" +#include "core/fxcrt/bytestring.h" #include "core/fxge/cfx_color.h" -#include "core/fxge/fx_dib.h" +#include "third_party/abseil-cpp/absl/types/optional.h" + +class CPDF_SimpleParser; class CPDF_DefaultAppearance { public: - CPDF_DefaultAppearance() {} - explicit CPDF_DefaultAppearance(const ByteString& csDA) : m_csDA(csDA) {} - CPDF_DefaultAppearance(const CPDF_DefaultAppearance& cDA) - : m_csDA(cDA.m_csDA) {} + CPDF_DefaultAppearance(); + explicit CPDF_DefaultAppearance(const ByteString& csDA); + CPDF_DefaultAppearance(const CPDF_DefaultAppearance& cDA); + ~CPDF_DefaultAppearance(); - Optional<ByteString> GetFont(float* fFontSize); + absl::optional<ByteString> GetFont(float* fFontSize) const; - Optional<CFX_Color::Type> GetColor(float fc[4]); - std::pair<Optional<CFX_Color::Type>, FX_ARGB> GetColor(); + absl::optional<CFX_Color> GetColor() const; + absl::optional<CFX_Color::TypeAndARGB> GetColorARGB() const; - bool FindTagParamFromStartForTesting(CPDF_SimpleParser* parser, - ByteStringView token, - int nParams); + static bool FindTagParamFromStartForTesting(CPDF_SimpleParser* parser, + ByteStringView token, + int nParams); private: - ByteString m_csDA; + const ByteString m_csDA; }; #endif // CORE_FPDFDOC_CPDF_DEFAULTAPPEARANCE_H_
diff --git a/core/fpdfdoc/cpdf_defaultappearance_unittest.cpp b/core/fpdfdoc/cpdf_defaultappearance_unittest.cpp index 6f6c525..86bac27 100644 --- a/core/fpdfdoc/cpdf_defaultappearance_unittest.cpp +++ b/core/fpdfdoc/cpdf_defaultappearance_unittest.cpp
@@ -1,9 +1,12 @@ -// Copyright 2018 PDFium Authors. All rights reserved. +// Copyright 2018 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "core/fpdfdoc/cpdf_defaultappearance.h" +#include <iterator> + +#include "core/fpdfapi/parser/cpdf_simple_parser.h" #include "testing/gtest/include/gtest/gtest.h" #include "testing/test_support.h" #include "third_party/base/span.h" @@ -35,13 +38,12 @@ STR_IN_TEST_CASE("1 2 3 4 5 6 7 8 cm", "cm", 6, true, 3), }; - CPDF_DefaultAppearance da; - for (size_t i = 0; i < FX_ArraySize(test_data); ++i) { + for (size_t i = 0; i < std::size(test_data); ++i) { CPDF_SimpleParser parser( pdfium::make_span(test_data[i].input, test_data[i].input_size)); EXPECT_EQ(test_data[i].result, - da.FindTagParamFromStartForTesting(&parser, test_data[i].token, - test_data[i].num_params)) + CPDF_DefaultAppearance::FindTagParamFromStartForTesting( + &parser, test_data[i].token, test_data[i].num_params)) << " for case " << i; EXPECT_EQ(test_data[i].result_pos, parser.GetCurPos()) << " for case " << i; }
diff --git a/core/fpdfdoc/cpdf_dest.cpp b/core/fpdfdoc/cpdf_dest.cpp index 1a07acf..b7682e1 100644 --- a/core/fpdfdoc/cpdf_dest.cpp +++ b/core/fpdfdoc/cpdf_dest.cpp
@@ -1,4 +1,4 @@ -// Copyright 2016 PDFium Authors. All rights reserved. +// Copyright 2016 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -7,42 +7,54 @@ #include "core/fpdfdoc/cpdf_dest.h" #include <algorithm> +#include <iterator> +#include <utility> #include "core/fpdfapi/parser/cpdf_array.h" #include "core/fpdfapi/parser/cpdf_document.h" #include "core/fpdfapi/parser/cpdf_name.h" #include "core/fpdfapi/parser/cpdf_number.h" +#include "core/fpdfdoc/cpdf_nametree.h" namespace { // These arrays are indexed by the PDFDEST_VIEW_* constants. // Last element is a sentinel. -const char* const g_sZoomModes[] = {"Unknown", "XYZ", "Fit", "FitH", - "FitV", "FitR", "FitB", "FitBH", - "FitBV", nullptr}; +const char* const kZoomModes[] = {"Unknown", "XYZ", "Fit", "FitH", "FitV", + "FitR", "FitB", "FitBH", "FitBV", nullptr}; -const uint8_t g_sZoomModeMaxParamCount[] = {0, 3, 0, 1, 1, 4, 0, 1, 1, 0}; +constexpr uint8_t kZoomModeMaxParamCount[] = {0, 3, 0, 1, 1, 4, 0, 1, 1, 0}; -static_assert(FX_ArraySize(g_sZoomModes) == - FX_ArraySize(g_sZoomModeMaxParamCount), +static_assert(std::size(kZoomModes) == std::size(kZoomModeMaxParamCount), "Zoom mode count Mismatch"); } // namespace -CPDF_Dest::CPDF_Dest() {} - -CPDF_Dest::CPDF_Dest(const CPDF_Array* pArray) : m_pArray(pArray) {} +CPDF_Dest::CPDF_Dest(RetainPtr<const CPDF_Array> pArray) + : m_pArray(std::move(pArray)) {} CPDF_Dest::CPDF_Dest(const CPDF_Dest& that) = default; -CPDF_Dest::~CPDF_Dest() {} +CPDF_Dest::~CPDF_Dest() = default; + +// static +CPDF_Dest CPDF_Dest::Create(CPDF_Document* pDoc, + RetainPtr<const CPDF_Object> pDest) { + if (!pDest) + return CPDF_Dest(nullptr); + + if (pDest->IsString() || pDest->IsName()) + return CPDF_Dest(CPDF_NameTree::LookupNamedDest(pDoc, pDest->GetString())); + + return CPDF_Dest(ToArray(pDest)); +} int CPDF_Dest::GetDestPageIndex(CPDF_Document* pDoc) const { if (!m_pArray) return -1; - const CPDF_Object* pPage = m_pArray->GetDirectObjectAt(0); + RetainPtr<const CPDF_Object> pPage = m_pArray->GetDirectObjectAt(0); if (!pPage) return -1; @@ -55,17 +67,28 @@ return pDoc->GetPageIndex(pPage->GetObjNum()); } +std::vector<float> CPDF_Dest::GetScrollPositionArray() const { + std::vector<float> result; + if (m_pArray) { + // Skip over index 0 which contains destination page details, and index 1 + // which contains a parameter that describes the rest of the array. + for (size_t i = 2; i < m_pArray->size(); i++) + result.push_back(m_pArray->GetFloatAt(i)); + } + return result; +} + int CPDF_Dest::GetZoomMode() const { if (!m_pArray) return 0; - const CPDF_Object* pArray = m_pArray->GetDirectObjectAt(1); + RetainPtr<const CPDF_Object> pArray = m_pArray->GetDirectObjectAt(1); if (!pArray) return 0; ByteString mode = pArray->GetString(); - for (int i = 1; g_sZoomModes[i]; ++i) { - if (mode == g_sZoomModes[i]) + for (int i = 1; kZoomModes[i]; ++i) { + if (mode == kZoomModes[i]) return i; } @@ -88,13 +111,14 @@ if (m_pArray->size() < 5) return false; - const CPDF_Name* xyz = ToName(m_pArray->GetDirectObjectAt(1)); + RetainPtr<const CPDF_Name> xyz = ToName(m_pArray->GetDirectObjectAt(1)); if (!xyz || xyz->GetString() != "XYZ") return false; - const CPDF_Number* numX = ToNumber(m_pArray->GetDirectObjectAt(2)); - const CPDF_Number* numY = ToNumber(m_pArray->GetDirectObjectAt(3)); - const CPDF_Number* numZoom = ToNumber(m_pArray->GetDirectObjectAt(4)); + RetainPtr<const CPDF_Number> numX = ToNumber(m_pArray->GetDirectObjectAt(2)); + RetainPtr<const CPDF_Number> numY = ToNumber(m_pArray->GetDirectObjectAt(3)); + RetainPtr<const CPDF_Number> numZoom = + ToNumber(m_pArray->GetDirectObjectAt(4)); // If the value is a CPDF_Null then ToNumber will return nullptr. *pHasX = !!numX; @@ -118,15 +142,15 @@ return true; } -unsigned long CPDF_Dest::GetNumParams() const { +size_t CPDF_Dest::GetNumParams() const { if (!m_pArray || m_pArray->size() < 2) return 0; - unsigned long maxParamsForFitType = g_sZoomModeMaxParamCount[GetZoomMode()]; - unsigned long numParamsInArray = m_pArray->size() - 2; + size_t maxParamsForFitType = kZoomModeMaxParamCount[GetZoomMode()]; + size_t numParamsInArray = m_pArray->size() - 2; return std::min(maxParamsForFitType, numParamsInArray); } -float CPDF_Dest::GetParam(int index) const { - return m_pArray ? m_pArray->GetNumberAt(2 + index) : 0; +float CPDF_Dest::GetParam(size_t index) const { + return m_pArray ? m_pArray->GetFloatAt(2 + index) : 0; }
diff --git a/core/fpdfdoc/cpdf_dest.h b/core/fpdfdoc/cpdf_dest.h index c215634..c32c7da 100644 --- a/core/fpdfdoc/cpdf_dest.h +++ b/core/fpdfdoc/cpdf_dest.h
@@ -1,4 +1,4 @@ -// Copyright 2016 PDFium Authors. All rights reserved. +// Copyright 2016 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -7,29 +7,34 @@ #ifndef CORE_FPDFDOC_CPDF_DEST_H_ #define CORE_FPDFDOC_CPDF_DEST_H_ -#include "core/fxcrt/fx_string.h" -#include "core/fxcrt/fx_system.h" +#include <vector> + +#include "core/fpdfapi/parser/cpdf_array.h" #include "core/fxcrt/retain_ptr.h" class CPDF_Document; -class CPDF_Array; +class CPDF_Object; class CPDF_Dest { public: - CPDF_Dest(); - explicit CPDF_Dest(const CPDF_Array* pArray); + explicit CPDF_Dest(RetainPtr<const CPDF_Array> pArray); CPDF_Dest(const CPDF_Dest& that); ~CPDF_Dest(); + // Use when |pDest| is an object of an unknown type. Can pass in nullptr. + static CPDF_Dest Create(CPDF_Document* pDoc, + RetainPtr<const CPDF_Object> pDest); + const CPDF_Array* GetArray() const { return m_pArray.Get(); } + int GetDestPageIndex(CPDF_Document* pDoc) const; + std::vector<float> GetScrollPositionArray() const; // Returns the zoom mode, as one of the PDFDEST_VIEW_* values in fpdf_doc.h. int GetZoomMode() const; - unsigned long GetNumParams() const; - float GetParam(int index) const; - + size_t GetNumParams() const; + float GetParam(size_t index) const; bool GetXYZ(bool* pHasX, bool* pHasY, bool* pHasZoom,
diff --git a/core/fpdfdoc/cpdf_dest_unittest.cpp b/core/fpdfdoc/cpdf_dest_unittest.cpp index 07e46b3..ae2d979 100644 --- a/core/fpdfdoc/cpdf_dest_unittest.cpp +++ b/core/fpdfdoc/cpdf_dest_unittest.cpp
@@ -1,15 +1,16 @@ -// Copyright 2016 PDFium Authors. All rights reserved. +// Copyright 2016 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "core/fpdfdoc/cpdf_dest.h" +#include <memory> + #include "core/fpdfapi/parser/cpdf_array.h" #include "core/fpdfapi/parser/cpdf_name.h" #include "core/fpdfapi/parser/cpdf_null.h" #include "core/fpdfapi/parser/cpdf_number.h" #include "testing/gtest/include/gtest/gtest.h" -#include "third_party/base/ptr_util.h" TEST(cpdf_dest, GetXYZ) { bool hasX; @@ -21,23 +22,23 @@ // |array| must outlive |dest|. auto array = pdfium::MakeRetain<CPDF_Array>(); - array->AddNew<CPDF_Number>(0); // Page Index. - array->AddNew<CPDF_Name>("XYZ"); - array->AddNew<CPDF_Number>(4); // X + array->AppendNew<CPDF_Number>(0); // Page Index. + array->AppendNew<CPDF_Name>("XYZ"); + array->AppendNew<CPDF_Number>(4); // X { - auto dest = pdfium::MakeUnique<CPDF_Dest>(); - EXPECT_FALSE(dest->GetXYZ(&hasX, &hasY, &hasZoom, &x, &y, &zoom)); + CPDF_Dest dest(nullptr); + EXPECT_FALSE(dest.GetXYZ(&hasX, &hasY, &hasZoom, &x, &y, &zoom)); } { // Not enough entries. - auto dest = pdfium::MakeUnique<CPDF_Dest>(array.Get()); - EXPECT_FALSE(dest->GetXYZ(&hasX, &hasY, &hasZoom, &x, &y, &zoom)); + CPDF_Dest dest(array); + EXPECT_FALSE(dest.GetXYZ(&hasX, &hasY, &hasZoom, &x, &y, &zoom)); } - array->AddNew<CPDF_Number>(5); // Y - array->AddNew<CPDF_Number>(6); // Zoom. + array->AppendNew<CPDF_Number>(5); // Y + array->AppendNew<CPDF_Number>(6); // Zoom. { - auto dest = pdfium::MakeUnique<CPDF_Dest>(array.Get()); - EXPECT_TRUE(dest->GetXYZ(&hasX, &hasY, &hasZoom, &x, &y, &zoom)); + CPDF_Dest dest(array); + EXPECT_TRUE(dest.GetXYZ(&hasX, &hasY, &hasZoom, &x, &y, &zoom)); EXPECT_TRUE(hasX); EXPECT_TRUE(hasY); EXPECT_TRUE(hasZoom); @@ -48,8 +49,8 @@ // Set zoom to 0. array->SetNewAt<CPDF_Number>(4, 0); { - auto dest = pdfium::MakeUnique<CPDF_Dest>(array.Get()); - EXPECT_TRUE(dest->GetXYZ(&hasX, &hasY, &hasZoom, &x, &y, &zoom)); + CPDF_Dest dest(array); + EXPECT_TRUE(dest.GetXYZ(&hasX, &hasY, &hasZoom, &x, &y, &zoom)); EXPECT_FALSE(hasZoom); } // Set values to null. @@ -57,8 +58,8 @@ array->SetNewAt<CPDF_Null>(3); array->SetNewAt<CPDF_Null>(4); { - auto dest = pdfium::MakeUnique<CPDF_Dest>(array.Get()); - EXPECT_TRUE(dest->GetXYZ(&hasX, &hasY, &hasZoom, &x, &y, &zoom)); + CPDF_Dest dest(array); + EXPECT_TRUE(dest.GetXYZ(&hasX, &hasY, &hasZoom, &x, &y, &zoom)); EXPECT_FALSE(hasX); EXPECT_FALSE(hasY); EXPECT_FALSE(hasZoom);
diff --git a/core/fpdfdoc/cpdf_filespec.cpp b/core/fpdfdoc/cpdf_filespec.cpp index 506e176..2e982b2 100644 --- a/core/fpdfdoc/cpdf_filespec.cpp +++ b/core/fpdfdoc/cpdf_filespec.cpp
@@ -1,4 +1,4 @@ -// Copyright 2016 PDFium Authors. All rights reserved. +// Copyright 2016 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -6,7 +6,8 @@ #include "core/fpdfdoc/cpdf_filespec.h" -#include <vector> +#include <iterator> +#include <utility> #include "build/build_config.h" #include "constants/stream_dict_common.h" @@ -17,15 +18,17 @@ #include "core/fpdfapi/parser/cpdf_string.h" #include "core/fpdfapi/parser/fpdf_parser_decode.h" #include "core/fxcrt/fx_system.h" +#include "third_party/base/check.h" +#include "third_party/base/notreached.h" namespace { -#if defined(OS_MACOSX) || defined(OS_WIN) +#if BUILDFLAG(IS_APPLE) || BUILDFLAG(IS_WIN) WideString ChangeSlashToPlatform(const wchar_t* str) { WideString result; while (*str) { if (*str == '/') { -#if defined(OS_MACOSX) +#if BUILDFLAG(IS_APPLE) result += L':'; #else result += L'\\'; @@ -50,30 +53,26 @@ } return result; } -#endif // defined(OS_MACOSX) || defined(OS_WIN) +#endif // BUILDFLAG(IS_APPLE) || BUILDFLAG(IS_WIN) } // namespace -CPDF_FileSpec::CPDF_FileSpec(const CPDF_Object* pObj) : m_pObj(pObj) { - ASSERT(m_pObj); +CPDF_FileSpec::CPDF_FileSpec(RetainPtr<const CPDF_Object> pObj) + : m_pObj(std::move(pObj)) { + DCHECK(m_pObj); } -CPDF_FileSpec::CPDF_FileSpec(CPDF_Object* pObj) - : m_pObj(pObj), m_pWritableObj(pObj) { - ASSERT(m_pObj); -} - -CPDF_FileSpec::~CPDF_FileSpec() {} +CPDF_FileSpec::~CPDF_FileSpec() = default; WideString CPDF_FileSpec::DecodeFileName(const WideString& filepath) { if (filepath.GetLength() <= 1) return WideString(); -#if defined(OS_MACOSX) +#if BUILDFLAG(IS_APPLE) if (filepath.First(sizeof("/Mac") - 1) == WideStringView(L"/Mac")) return ChangeSlashToPlatform(filepath.c_str() + 1); return ChangeSlashToPlatform(filepath.c_str()); -#elif defined(OS_WIN) +#elif BUILDFLAG(IS_WIN) if (filepath[0] != L'/') return ChangeSlashToPlatform(filepath.c_str()); @@ -98,21 +97,23 @@ WideString CPDF_FileSpec::GetFileName() const { WideString csFileName; if (const CPDF_Dictionary* pDict = m_pObj->AsDictionary()) { - const CPDF_String* pUF = ToString(pDict->GetDirectObjectFor("UF")); + RetainPtr<const CPDF_String> pUF = + ToString(pDict->GetDirectObjectFor("UF")); if (pUF) csFileName = pUF->GetUnicodeText(); if (csFileName.IsEmpty()) { - const CPDF_String* pK = + RetainPtr<const CPDF_String> pK = ToString(pDict->GetDirectObjectFor(pdfium::stream::kF)); if (pK) csFileName = WideString::FromDefANSI(pK->GetString().AsStringView()); } - if (pDict->GetStringFor("FS") == "URL") + if (pDict->GetByteStringFor("FS") == "URL") return csFileName; if (csFileName.IsEmpty()) { for (const auto* key : {"DOS", "Mac", "Unix"}) { - const CPDF_String* pValue = ToString(pDict->GetDirectObjectFor(key)); + RetainPtr<const CPDF_String> pValue = + ToString(pDict->GetDirectObjectFor(key)); if (pValue) { csFileName = WideString::FromDefANSI(pValue->GetString().AsStringView()); @@ -126,24 +127,24 @@ return DecodeFileName(csFileName); } -const CPDF_Stream* CPDF_FileSpec::GetFileStream() const { +RetainPtr<const CPDF_Stream> CPDF_FileSpec::GetFileStream() const { const CPDF_Dictionary* pDict = m_pObj->AsDictionary(); if (!pDict) return nullptr; // Get the embedded files dictionary. - const CPDF_Dictionary* pFiles = pDict->GetDictFor("EF"); + RetainPtr<const CPDF_Dictionary> pFiles = pDict->GetDictFor("EF"); if (!pFiles) return nullptr; // List of keys to check for the file specification string. // Follows the same precedence order as GetFileName(). static constexpr const char* kKeys[] = {"UF", "F", "DOS", "Mac", "Unix"}; - size_t end = pDict->GetStringFor("FS") == "URL" ? 2 : FX_ArraySize(kKeys); + size_t end = pDict->GetByteStringFor("FS") == "URL" ? 2 : std::size(kKeys); for (size_t i = 0; i < end; ++i) { ByteString key = kKeys[i]; if (!pDict->GetUnicodeTextFor(key).IsEmpty()) { - const CPDF_Stream* pStream = pFiles->GetStreamFor(key); + RetainPtr<const CPDF_Stream> pStream = pFiles->GetStreamFor(key); if (pStream) return pStream; } @@ -151,30 +152,25 @@ return nullptr; } -CPDF_Stream* CPDF_FileSpec::GetFileStream() { - return const_cast<CPDF_Stream*>( - static_cast<const CPDF_FileSpec*>(this)->GetFileStream()); -} - -const CPDF_Dictionary* CPDF_FileSpec::GetParamsDict() const { - const CPDF_Stream* pStream = GetFileStream(); +RetainPtr<const CPDF_Dictionary> CPDF_FileSpec::GetParamsDict() const { + RetainPtr<const CPDF_Stream> pStream = GetFileStream(); if (!pStream) return nullptr; - const CPDF_Dictionary* pDict = pStream->GetDict(); + RetainPtr<const CPDF_Dictionary> pDict = pStream->GetDict(); return pDict ? pDict->GetDictFor("Params") : nullptr; } -CPDF_Dictionary* CPDF_FileSpec::GetParamsDict() { - return const_cast<CPDF_Dictionary*>( - static_cast<const CPDF_FileSpec*>(this)->GetParamsDict()); +RetainPtr<CPDF_Dictionary> CPDF_FileSpec::GetMutableParamsDict() { + return pdfium::WrapRetain( + const_cast<CPDF_Dictionary*>(GetParamsDict().Get())); } WideString CPDF_FileSpec::EncodeFileName(const WideString& filepath) { if (filepath.GetLength() <= 1) return WideString(); -#if defined(OS_WIN) +#if BUILDFLAG(IS_WIN) if (filepath[1] == L':') { WideString result(L'/'); result += filepath[0]; @@ -190,7 +186,7 @@ if (filepath[0] == L'\\') return L'/' + ChangeSlashToPDF(filepath.c_str()); return ChangeSlashToPDF(filepath.c_str()); -#elif defined(OS_MACOSX) +#elif BUILDFLAG(IS_APPLE) if (filepath.First(sizeof("Mac") - 1).EqualsASCII("Mac")) return L'/' + ChangeSlashToPDF(filepath.c_str()); return ChangeSlashToPDF(filepath.c_str()); @@ -198,18 +194,3 @@ return WideString(filepath); #endif } - -void CPDF_FileSpec::SetFileName(const WideString& wsFileName) { - if (!m_pWritableObj) { - NOTREACHED(); - return; - } - - WideString wsStr = EncodeFileName(wsFileName); - if (m_pObj->IsString()) { - m_pWritableObj->SetString(wsStr.ToDefANSI()); - } else if (CPDF_Dictionary* pDict = m_pWritableObj->AsDictionary()) { - pDict->SetNewFor<CPDF_String>(pdfium::stream::kF, wsStr.ToDefANSI(), false); - pDict->SetNewFor<CPDF_String>("UF", wsStr); - } -}
diff --git a/core/fpdfdoc/cpdf_filespec.h b/core/fpdfdoc/cpdf_filespec.h index 820b948..d943811 100644 --- a/core/fpdfdoc/cpdf_filespec.h +++ b/core/fpdfdoc/cpdf_filespec.h
@@ -1,4 +1,4 @@ -// Copyright 2016 PDFium Authors. All rights reserved. +// Copyright 2016 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -7,10 +7,10 @@ #ifndef CORE_FPDFDOC_CPDF_FILESPEC_H_ #define CORE_FPDFDOC_CPDF_FILESPEC_H_ -#include "core/fxcrt/fx_string.h" #include "core/fxcrt/retain_ptr.h" #include "core/fxcrt/string_pool_template.h" #include "core/fxcrt/weak_ptr.h" +#include "core/fxcrt/widestring.h" class CPDF_Dictionary; class CPDF_Object; @@ -18,8 +18,7 @@ class CPDF_FileSpec { public: - explicit CPDF_FileSpec(const CPDF_Object* pObj); - explicit CPDF_FileSpec(CPDF_Object* pObj); + explicit CPDF_FileSpec(RetainPtr<const CPDF_Object> pObj); ~CPDF_FileSpec(); // Convert a platform dependent file name into pdf format. @@ -28,20 +27,13 @@ // Convert a pdf file name into platform dependent format. static WideString DecodeFileName(const WideString& filepath); - const CPDF_Object* GetObj() const { return m_pObj.Get(); } - CPDF_Object* GetObj() { return m_pWritableObj.Get(); } WideString GetFileName() const; - const CPDF_Stream* GetFileStream() const; - CPDF_Stream* GetFileStream(); - const CPDF_Dictionary* GetParamsDict() const; - CPDF_Dictionary* GetParamsDict(); - - // Set this file spec to refer to a file name (not a url). - void SetFileName(const WideString& wsFileName); + RetainPtr<const CPDF_Stream> GetFileStream() const; + RetainPtr<const CPDF_Dictionary> GetParamsDict() const; + RetainPtr<CPDF_Dictionary> GetMutableParamsDict(); private: RetainPtr<const CPDF_Object> const m_pObj; - RetainPtr<CPDF_Object> const m_pWritableObj; }; #endif // CORE_FPDFDOC_CPDF_FILESPEC_H_
diff --git a/core/fpdfdoc/cpdf_filespec_unittest.cpp b/core/fpdfdoc/cpdf_filespec_unittest.cpp index a075c5e..7c517a9 100644 --- a/core/fpdfdoc/cpdf_filespec_unittest.cpp +++ b/core/fpdfdoc/cpdf_filespec_unittest.cpp
@@ -1,7 +1,9 @@ -// Copyright 2016 PDFium Authors. All rights reserved. +// Copyright 2016 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include "core/fpdfdoc/cpdf_filespec.h" + #include <memory> #include <utility> #include <vector> @@ -12,11 +14,9 @@ #include "core/fpdfapi/parser/cpdf_number.h" #include "core/fpdfapi/parser/cpdf_stream.h" #include "core/fpdfapi/parser/cpdf_string.h" -#include "core/fpdfdoc/cpdf_filespec.h" -#include "core/fxcrt/fx_memory_wrappers.h" +#include "core/fxcrt/data_vector.h" #include "testing/gtest/include/gtest/gtest.h" #include "testing/test_support.h" -#include "third_party/base/ptr_util.h" TEST(cpdf_filespec, EncodeDecodeFileName) { static const std::vector<pdfium::NullTermWstrFuncTestData> test_data = { @@ -24,7 +24,7 @@ {L"", L""}, // only file name. {L"test.pdf", L"test.pdf"}, -#if defined(OS_WIN) +#if BUILDFLAG(IS_WIN) // With drive identifier. {L"r:\\pdfdocs\\spec.pdf", L"/r/pdfdocs/spec.pdf"}, // Relative path. @@ -35,7 +35,7 @@ {L"\\\\pdfdocs\\spec.pdf", L"/pdfdocs/spec.pdf"}, // Network resource name. It is not supported yet. // {L"pclib/eng:\\pdfdocs\\spec.pdf", L"/pclib/eng/pdfdocs/spec.pdf"}, -#elif defined(OS_MACOSX) +#elif BUILDFLAG(IS_APPLE) // Absolute path with colon separator. {L"Mac HD:PDFDocs:spec.pdf", L"/Mac HD/PDFDocs/spec.pdf"}, // Relative path with colon separator. @@ -62,10 +62,10 @@ { // String object. static const pdfium::NullTermWstrFuncTestData test_data = { -#if defined(OS_WIN) +#if BUILDFLAG(IS_WIN) L"/C/docs/test.pdf", L"C:\\docs\\test.pdf" -#elif defined(OS_MACOSX) +#elif BUILDFLAG(IS_APPLE) L"/Mac HD/docs/test.pdf", L"Mac HD:docs:test.pdf" #else @@ -74,19 +74,19 @@ #endif }; auto str_obj = pdfium::MakeRetain<CPDF_String>(nullptr, test_data.input); - CPDF_FileSpec file_spec(str_obj.Get()); + CPDF_FileSpec file_spec(str_obj); EXPECT_STREQ(test_data.expected, file_spec.GetFileName().c_str()); } { // Dictionary object. static const pdfium::NullTermWstrFuncTestData test_data[] = { -#if defined(OS_WIN) +#if BUILDFLAG(IS_WIN) {L"/C/docs/test.pdf", L"C:\\docs\\test.pdf"}, {L"/D/docs/test.pdf", L"D:\\docs\\test.pdf"}, {L"/E/docs/test.pdf", L"E:\\docs\\test.pdf"}, {L"/F/docs/test.pdf", L"F:\\docs\\test.pdf"}, {L"/G/docs/test.pdf", L"G:\\docs\\test.pdf"}, -#elif defined(OS_MACOSX) +#elif BUILDFLAG(IS_APPLE) {L"/Mac HD/docs1/test.pdf", L"Mac HD:docs1:test.pdf"}, {L"/Mac HD/docs2/test.pdf", L"Mac HD:docs2:test.pdf"}, {L"/Mac HD/docs3/test.pdf", L"Mac HD:docs3:test.pdf"}, @@ -102,12 +102,11 @@ }; // Keyword fields in reverse order of precedence to retrieve the file name. const char* const keywords[] = {"Unix", "Mac", "DOS", "F", "UF"}; - static_assert(FX_ArraySize(test_data) == FX_ArraySize(keywords), - "size mismatch"); + static_assert(std::size(test_data) == std::size(keywords), "size mismatch"); auto dict_obj = pdfium::MakeRetain<CPDF_Dictionary>(); - CPDF_FileSpec file_spec(dict_obj.Get()); + CPDF_FileSpec file_spec(dict_obj); EXPECT_TRUE(file_spec.GetFileName().IsEmpty()); - for (size_t i = 0; i < FX_ArraySize(keywords); ++i) { + for (size_t i = 0; i < std::size(keywords); ++i) { dict_obj->SetNewFor<CPDF_String>(keywords[i], test_data[i].input); EXPECT_STREQ(test_data[i].expected, file_spec.GetFileName().c_str()); } @@ -120,13 +119,13 @@ { // Invalid object. auto name_obj = pdfium::MakeRetain<CPDF_Name>(nullptr, "test.pdf"); - CPDF_FileSpec file_spec(name_obj.Get()); + CPDF_FileSpec file_spec(name_obj); EXPECT_TRUE(file_spec.GetFileName().IsEmpty()); } { // Invalid CPDF_Name objects in dictionary. See https://crbug.com/959183 auto dict_obj = pdfium::MakeRetain<CPDF_Dictionary>(); - CPDF_FileSpec file_spec(dict_obj.Get()); + CPDF_FileSpec file_spec(dict_obj); for (const char* key : {"Unix", "Mac", "DOS", "F", "UF"}) { dict_obj->SetNewFor<CPDF_Name>(key, "http://evil.org"); EXPECT_TRUE(file_spec.GetFileName().IsEmpty()); @@ -136,84 +135,49 @@ } } -TEST(cpdf_filespec, SetFileName) { - static const pdfium::NullTermWstrFuncTestData test_data = { -#if defined(OS_WIN) - L"C:\\docs\\test.pdf", - L"/C/docs/test.pdf" -#elif defined(OS_MACOSX) - L"Mac HD:docs:test.pdf", - L"/Mac HD/docs/test.pdf" -#else - L"/docs/test.pdf", - L"/docs/test.pdf" -#endif - }; - // String object. - auto str_obj = pdfium::MakeRetain<CPDF_String>(nullptr, L"babababa"); - CPDF_FileSpec file_spec1(str_obj.Get()); - file_spec1.SetFileName(test_data.input); - // Check internal object value. - EXPECT_STREQ(test_data.expected, str_obj->GetUnicodeText().c_str()); - // Check we can get the file name back. - EXPECT_STREQ(test_data.input, file_spec1.GetFileName().c_str()); - - // Dictionary object. - auto dict_obj = pdfium::MakeRetain<CPDF_Dictionary>(); - CPDF_FileSpec file_spec2(dict_obj.Get()); - file_spec2.SetFileName(test_data.input); - // Check internal object value. - EXPECT_STREQ(test_data.expected, dict_obj->GetUnicodeTextFor("F").c_str()); - EXPECT_STREQ(test_data.expected, dict_obj->GetUnicodeTextFor("UF").c_str()); - // Check we can get the file name back. - EXPECT_STREQ(test_data.input, file_spec2.GetFileName().c_str()); -} - TEST(cpdf_filespec, GetFileStream) { { // Invalid object. auto name_obj = pdfium::MakeRetain<CPDF_Name>(nullptr, "test.pdf"); - CPDF_FileSpec file_spec(name_obj.Get()); + CPDF_FileSpec file_spec(name_obj); EXPECT_FALSE(file_spec.GetFileStream()); } { // Dictionary object missing its embedded files dictionary. auto dict_obj = pdfium::MakeRetain<CPDF_Dictionary>(); - CPDF_FileSpec file_spec(dict_obj.Get()); + CPDF_FileSpec file_spec(dict_obj); EXPECT_FALSE(file_spec.GetFileStream()); } { // Dictionary object with an empty embedded files dictionary. auto dict_obj = pdfium::MakeRetain<CPDF_Dictionary>(); dict_obj->SetNewFor<CPDF_Dictionary>("EF"); - CPDF_FileSpec file_spec(dict_obj.Get()); + CPDF_FileSpec file_spec(dict_obj); EXPECT_FALSE(file_spec.GetFileStream()); } { // Dictionary object with a non-empty embedded files dictionary. auto dict_obj = pdfium::MakeRetain<CPDF_Dictionary>(); dict_obj->SetNewFor<CPDF_Dictionary>("EF"); - CPDF_FileSpec file_spec(dict_obj.Get()); + CPDF_FileSpec file_spec(dict_obj); const wchar_t file_name[] = L"test.pdf"; const char* const keys[] = {"Unix", "Mac", "DOS", "F", "UF"}; const char* const streams[] = {"test1", "test2", "test3", "test4", "test5"}; - static_assert(FX_ArraySize(keys) == FX_ArraySize(streams), "size mismatch"); - CPDF_Dictionary* file_dict = - file_spec.GetObj()->AsDictionary()->GetDictFor("EF"); + static_assert(std::size(keys) == std::size(streams), "size mismatch"); + RetainPtr<CPDF_Dictionary> file_dict = dict_obj->GetMutableDictFor("EF"); // Keys in reverse order of precedence to retrieve the file content stream. - for (size_t i = 0; i < FX_ArraySize(keys); ++i) { + for (size_t i = 0; i < std::size(keys); ++i) { // Set the file name. dict_obj->SetNewFor<CPDF_String>(keys[i], file_name); // Set the file stream. auto pDict = pdfium::MakeRetain<CPDF_Dictionary>(); size_t buf_len = strlen(streams[i]) + 1; - std::unique_ptr<uint8_t, FxFreeDeleter> buf(FX_Alloc(uint8_t, buf_len)); - memcpy(buf.get(), streams[i], buf_len); - file_dict->SetNewFor<CPDF_Stream>(keys[i], std::move(buf), buf_len, - std::move(pDict)); + file_dict->SetNewFor<CPDF_Stream>( + keys[i], DataVector<uint8_t>(streams[i], streams[i] + buf_len), + std::move(pDict)); // Check that the file content stream is as expected. EXPECT_STREQ( @@ -232,7 +196,7 @@ { // Invalid object. auto name_obj = pdfium::MakeRetain<CPDF_Name>(nullptr, "test.pdf"); - CPDF_FileSpec file_spec(name_obj.Get()); + CPDF_FileSpec file_spec(name_obj); EXPECT_FALSE(file_spec.GetParamsDict()); } { @@ -240,26 +204,26 @@ auto dict_obj = pdfium::MakeRetain<CPDF_Dictionary>(); dict_obj->SetNewFor<CPDF_Dictionary>("EF"); dict_obj->SetNewFor<CPDF_String>("UF", L"test.pdf"); - CPDF_FileSpec file_spec(dict_obj.Get()); + CPDF_FileSpec file_spec(dict_obj); EXPECT_FALSE(file_spec.GetParamsDict()); // Add a file stream to the embedded files dictionary. - CPDF_Dictionary* file_dict = - file_spec.GetObj()->AsDictionary()->GetDictFor("EF"); + RetainPtr<CPDF_Dictionary> file_dict = dict_obj->GetMutableDictFor("EF"); auto pDict = pdfium::MakeRetain<CPDF_Dictionary>(); - std::unique_ptr<uint8_t, FxFreeDeleter> buf(FX_Alloc(uint8_t, 6)); - memcpy(buf.get(), "hello", 6); - file_dict->SetNewFor<CPDF_Stream>("UF", std::move(buf), 6, - std::move(pDict)); + static constexpr char kHello[] = "hello"; + file_dict->SetNewFor<CPDF_Stream>( + "UF", DataVector<uint8_t>(std::begin(kHello), std::end(kHello)), + std::move(pDict)); // Add a params dictionary to the file stream. - CPDF_Stream* stream = file_dict->GetStreamFor("UF"); - CPDF_Dictionary* stream_dict = stream->GetDict(); + RetainPtr<CPDF_Stream> stream = file_dict->GetMutableStreamFor("UF"); + RetainPtr<CPDF_Dictionary> stream_dict = stream->GetMutableDict(); stream_dict->SetNewFor<CPDF_Dictionary>("Params"); EXPECT_TRUE(file_spec.GetParamsDict()); // Add a parameter to the params dictionary. - CPDF_Dictionary* params_dict = stream_dict->GetDictFor("Params"); + RetainPtr<CPDF_Dictionary> params_dict = + stream_dict->GetMutableDictFor("Params"); params_dict->SetNewFor<CPDF_Number>("Size", 6); EXPECT_EQ(6, file_spec.GetParamsDict()->GetIntegerFor("Size")); }
diff --git a/core/fpdfdoc/cpdf_formcontrol.cpp b/core/fpdfdoc/cpdf_formcontrol.cpp index b98afba..31bbdf3 100644 --- a/core/fpdfdoc/cpdf_formcontrol.cpp +++ b/core/fpdfdoc/cpdf_formcontrol.cpp
@@ -1,4 +1,4 @@ -// Copyright 2016 PDFium Authors. All rights reserved. +// Copyright 2016 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -6,32 +6,45 @@ #include "core/fpdfdoc/cpdf_formcontrol.h" -#include <algorithm> +#include <iterator> +#include <utility> +#include "constants/form_fields.h" #include "core/fpdfapi/font/cpdf_font.h" #include "core/fpdfapi/page/cpdf_docpagedata.h" #include "core/fpdfapi/parser/cpdf_array.h" #include "core/fpdfapi/parser/cpdf_dictionary.h" -#include "core/fpdfapi/parser/cpdf_document.h" #include "core/fpdfapi/parser/cpdf_name.h" #include "core/fpdfapi/parser/cpdf_stream.h" #include "core/fpdfapi/parser/fpdf_parser_decode.h" #include "core/fpdfapi/parser/fpdf_parser_utility.h" #include "core/fpdfdoc/cpdf_interactiveform.h" +#include "third_party/base/check.h" namespace { -const char* const g_sHighlightingMode[] = { - // Must match order of HighlightingMode enum. - "N", "I", "O", "P", "T"}; +constexpr char kHighlightModes[] = {'N', 'I', 'O', 'P', 'T'}; + +// Order of |kHighlightModes| must match order of HighlightingMode enum. +static_assert(kHighlightModes[CPDF_FormControl::kNone] == 'N', + "HighlightingMode mismatch"); +static_assert(kHighlightModes[CPDF_FormControl::kInvert] == 'I', + "HighlightingMode mismatch"); +static_assert(kHighlightModes[CPDF_FormControl::kOutline] == 'O', + "HighlightingMode mismatch"); +static_assert(kHighlightModes[CPDF_FormControl::kPush] == 'P', + "HighlightingMode mismatch"); +static_assert(kHighlightModes[CPDF_FormControl::kToggle] == 'T', + "HighlightingMode mismatch"); } // namespace CPDF_FormControl::CPDF_FormControl(CPDF_FormField* pField, - CPDF_Dictionary* pWidgetDict) - : m_pField(pField), - m_pWidgetDict(pWidgetDict), - m_pForm(m_pField->GetForm()) {} + RetainPtr<CPDF_Dictionary> pWidgetDict, + CPDF_InteractiveForm* pForm) + : m_pField(pField), m_pWidgetDict(std::move(pWidgetDict)), m_pForm(pForm) { + DCHECK(m_pWidgetDict); +} CPDF_FormControl::~CPDF_FormControl() = default; @@ -40,16 +53,15 @@ } ByteString CPDF_FormControl::GetOnStateName() const { - ASSERT(GetType() == CPDF_FormField::kCheckBox || + DCHECK(GetType() == CPDF_FormField::kCheckBox || GetType() == CPDF_FormField::kRadioButton); - ByteString csOn; - CPDF_Dictionary* pAP = m_pWidgetDict->GetDictFor("AP"); + RetainPtr<const CPDF_Dictionary> pAP = m_pWidgetDict->GetDictFor("AP"); if (!pAP) - return csOn; + return ByteString(); - CPDF_Dictionary* pN = pAP->GetDictFor("N"); + RetainPtr<const CPDF_Dictionary> pN = pAP->GetDictFor("N"); if (!pN) - return csOn; + return ByteString(); CPDF_DictionaryLocker locker(pN); for (const auto& it : locker) { @@ -60,41 +72,40 @@ } ByteString CPDF_FormControl::GetCheckedAPState() const { - ASSERT(GetType() == CPDF_FormField::kCheckBox || + DCHECK(GetType() == CPDF_FormField::kCheckBox || GetType() == CPDF_FormField::kRadioButton); ByteString csOn = GetOnStateName(); - if (ToArray(CPDF_FormField::GetFieldAttr(m_pField->GetDict(), "Opt"))) - csOn = ByteString::Format("%d", m_pField->GetControlIndex(this)); + if (ToArray(m_pField->GetFieldAttr("Opt"))) + csOn = ByteString::FormatInteger(m_pField->GetControlIndex(this)); if (csOn.IsEmpty()) csOn = "Yes"; return csOn; } WideString CPDF_FormControl::GetExportValue() const { - ASSERT(GetType() == CPDF_FormField::kCheckBox || + DCHECK(GetType() == CPDF_FormField::kCheckBox || GetType() == CPDF_FormField::kRadioButton); ByteString csOn = GetOnStateName(); - CPDF_Array* pArray = - ToArray(CPDF_FormField::GetFieldAttr(m_pField->GetDict(), "Opt")); + RetainPtr<const CPDF_Array> pArray = ToArray(m_pField->GetFieldAttr("Opt")); if (pArray) - csOn = pArray->GetStringAt(m_pField->GetControlIndex(this)); + csOn = pArray->GetByteStringAt(m_pField->GetControlIndex(this)); if (csOn.IsEmpty()) csOn = "Yes"; return PDF_DecodeText(csOn.raw_span()); } bool CPDF_FormControl::IsChecked() const { - ASSERT(GetType() == CPDF_FormField::kCheckBox || + DCHECK(GetType() == CPDF_FormField::kCheckBox || GetType() == CPDF_FormField::kRadioButton); ByteString csOn = GetOnStateName(); - ByteString csAS = m_pWidgetDict->GetStringFor("AS"); + ByteString csAS = m_pWidgetDict->GetByteStringFor("AS"); return csAS == csOn; } bool CPDF_FormControl::IsDefaultChecked() const { - ASSERT(GetType() == CPDF_FormField::kCheckBox || + DCHECK(GetType() == CPDF_FormField::kCheckBox || GetType() == CPDF_FormField::kRadioButton); - CPDF_Object* pDV = CPDF_FormField::GetFieldAttr(m_pField->GetDict(), "DV"); + RetainPtr<const CPDF_Object> pDV = m_pField->GetFieldAttr("DV"); if (!pDV) return false; @@ -104,9 +115,9 @@ } void CPDF_FormControl::CheckControl(bool bChecked) { - ASSERT(GetType() == CPDF_FormField::kCheckBox || + DCHECK(GetType() == CPDF_FormField::kCheckBox || GetType() == CPDF_FormField::kRadioButton); - ByteString csOldAS = m_pWidgetDict->GetStringFor("AS", "Off"); + ByteString csOldAS = m_pWidgetDict->GetByteStringFor("AS", "Off"); ByteString csAS = "Off"; if (bChecked) csAS = GetOnStateName(); @@ -117,20 +128,17 @@ CPDF_FormControl::HighlightingMode CPDF_FormControl::GetHighlightingMode() const { - if (!m_pWidgetDict) - return Invert; - - ByteString csH = m_pWidgetDict->GetStringFor("H", "I"); - for (size_t i = 0; i < FX_ArraySize(g_sHighlightingMode); ++i) { - if (csH == g_sHighlightingMode[i]) + ByteString csH = m_pWidgetDict->GetByteStringFor("H", "I"); + for (size_t i = 0; i < std::size(kHighlightModes); ++i) { + // TODO(tsepez): disambiguate string ctors. + if (csH == ByteStringView(kHighlightModes[i])) return static_cast<HighlightingMode>(i); } - return Invert; + return kInvert; } CPDF_ApSettings CPDF_FormControl::GetMK() const { - return CPDF_ApSettings(m_pWidgetDict ? m_pWidgetDict->GetDictFor("MK") - : nullptr); + return CPDF_ApSettings(m_pWidgetDict->GetMutableDictFor("MK")); } bool CPDF_FormControl::HasMKEntry(const ByteString& csEntry) const { @@ -141,25 +149,25 @@ return GetMK().GetRotation(); } -FX_ARGB CPDF_FormControl::GetColor(int& iColorType, const ByteString& csEntry) { - return GetMK().GetColor(iColorType, csEntry); +CFX_Color::TypeAndARGB CPDF_FormControl::GetColorARGB( + const ByteString& csEntry) { + return GetMK().GetColorARGB(csEntry); } -float CPDF_FormControl::GetOriginalColor(int index, const ByteString& csEntry) { - return GetMK().GetOriginalColor(index, csEntry); +float CPDF_FormControl::GetOriginalColorComponent(int index, + const ByteString& csEntry) { + return GetMK().GetOriginalColorComponent(index, csEntry); } -void CPDF_FormControl::GetOriginalColor(int& iColorType, - float fc[4], - const ByteString& csEntry) { - GetMK().GetOriginalColor(iColorType, fc, csEntry); +CFX_Color CPDF_FormControl::GetOriginalColor(const ByteString& csEntry) { + return GetMK().GetOriginalColor(csEntry); } WideString CPDF_FormControl::GetCaption(const ByteString& csEntry) const { return GetMK().GetCaption(csEntry); } -CPDF_Stream* CPDF_FormControl::GetIcon(const ByteString& csEntry) { +RetainPtr<CPDF_Stream> CPDF_FormControl::GetIcon(const ByteString& csEntry) { return GetMK().GetIcon(csEntry); } @@ -171,43 +179,23 @@ return GetMK().GetTextPosition(); } -CPDF_Action CPDF_FormControl::GetAction() const { - if (!m_pWidgetDict) - return CPDF_Action(nullptr); - - if (m_pWidgetDict->KeyExist("A")) - return CPDF_Action(m_pWidgetDict->GetDictFor("A")); - - CPDF_Object* pObj = CPDF_FormField::GetFieldAttr(m_pField->GetDict(), "A"); - return CPDF_Action(pObj ? pObj->GetDict() : nullptr); -} - -CPDF_AAction CPDF_FormControl::GetAdditionalAction() const { - if (!m_pWidgetDict) - return CPDF_AAction(nullptr); - - if (m_pWidgetDict->KeyExist("AA")) - return CPDF_AAction(m_pWidgetDict->GetDictFor("AA")); - return m_pField->GetAdditionalAction(); -} - CPDF_DefaultAppearance CPDF_FormControl::GetDefaultAppearance() const { - if (!m_pWidgetDict) - return CPDF_DefaultAppearance(); + if (m_pWidgetDict->KeyExist(pdfium::form_fields::kDA)) { + return CPDF_DefaultAppearance( + m_pWidgetDict->GetByteStringFor(pdfium::form_fields::kDA)); + } + RetainPtr<const CPDF_Object> pObj = + m_pField->GetFieldAttr(pdfium::form_fields::kDA); + if (pObj) + return CPDF_DefaultAppearance(pObj->GetString()); - if (m_pWidgetDict->KeyExist("DA")) - return CPDF_DefaultAppearance(m_pWidgetDict->GetStringFor("DA")); - - CPDF_Object* pObj = CPDF_FormField::GetFieldAttr(m_pField->GetDict(), "DA"); - if (!pObj) - return m_pForm->GetDefaultAppearance(); - return CPDF_DefaultAppearance(pObj->GetString()); + return m_pForm->GetDefaultAppearance(); } -Optional<WideString> CPDF_FormControl::GetDefaultControlFontName() const { +absl::optional<WideString> CPDF_FormControl::GetDefaultControlFontName() const { RetainPtr<CPDF_Font> pFont = GetDefaultControlFont(); if (!pFont) - return {}; + return absl::nullopt; return WideString::FromDefANSI(pFont->GetBaseFontName().AsStringView()); } @@ -215,53 +203,55 @@ RetainPtr<CPDF_Font> CPDF_FormControl::GetDefaultControlFont() const { float fFontSize; CPDF_DefaultAppearance cDA = GetDefaultAppearance(); - Optional<ByteString> csFontNameTag = cDA.GetFont(&fFontSize); - if (!csFontNameTag || csFontNameTag->IsEmpty()) + absl::optional<ByteString> csFontNameTag = cDA.GetFont(&fFontSize); + if (!csFontNameTag.has_value() || csFontNameTag->IsEmpty()) return nullptr; - CPDF_Object* pObj = CPDF_FormField::GetFieldAttr(m_pWidgetDict.Get(), "DR"); - if (CPDF_Dictionary* pDict = ToDictionary(pObj)) { - CPDF_Dictionary* pFonts = pDict->GetDictFor("Font"); - if (ValidateFontResourceDict(pFonts)) { - CPDF_Dictionary* pElement = pFonts->GetDictFor(*csFontNameTag); + RetainPtr<CPDF_Dictionary> pDRDict = ToDictionary( + CPDF_FormField::GetMutableFieldAttrForDict(m_pWidgetDict.Get(), "DR")); + if (pDRDict) { + RetainPtr<CPDF_Dictionary> pFonts = pDRDict->GetMutableDictFor("Font"); + if (ValidateFontResourceDict(pFonts.Get())) { + RetainPtr<CPDF_Dictionary> pElement = + pFonts->GetMutableDictFor(csFontNameTag.value()); if (pElement) { - auto* pData = CPDF_DocPageData::FromDocument(m_pForm->GetDocument()); - RetainPtr<CPDF_Font> pFont = pData->GetFont(pElement); + RetainPtr<CPDF_Font> pFont = + m_pForm->GetFontForElement(std::move(pElement)); if (pFont) return pFont; } } } - RetainPtr<CPDF_Font> pFormFont = m_pForm->GetFormFont(*csFontNameTag); + RetainPtr<CPDF_Font> pFormFont = m_pForm->GetFormFont(csFontNameTag.value()); if (pFormFont) return pFormFont; - CPDF_Dictionary* pPageDict = m_pWidgetDict->GetDictFor("P"); - CPDF_Dictionary* pDict = - ToDictionary(CPDF_FormField::GetFieldAttr(pPageDict, "Resources")); + RetainPtr<CPDF_Dictionary> pPageDict = m_pWidgetDict->GetMutableDictFor("P"); + RetainPtr<CPDF_Dictionary> pDict = ToDictionary( + CPDF_FormField::GetMutableFieldAttrForDict(pPageDict.Get(), "Resources")); if (!pDict) return nullptr; - CPDF_Dictionary* pFonts = pDict->GetDictFor("Font"); - if (!ValidateFontResourceDict(pFonts)) + RetainPtr<CPDF_Dictionary> pFonts = pDict->GetMutableDictFor("Font"); + if (!ValidateFontResourceDict(pFonts.Get())) return nullptr; - CPDF_Dictionary* pElement = pFonts->GetDictFor(*csFontNameTag); + RetainPtr<CPDF_Dictionary> pElement = + pFonts->GetMutableDictFor(csFontNameTag.value()); if (!pElement) return nullptr; - auto* pDocPageData = CPDF_DocPageData::FromDocument(m_pForm->GetDocument()); - return pDocPageData->GetFont(pElement); + return m_pForm->GetFontForElement(std::move(pElement)); } int CPDF_FormControl::GetControlAlignment() const { - if (!m_pWidgetDict) - return 0; - if (m_pWidgetDict->KeyExist("Q")) - return m_pWidgetDict->GetIntegerFor("Q", 0); + if (m_pWidgetDict->KeyExist(pdfium::form_fields::kQ)) + return m_pWidgetDict->GetIntegerFor(pdfium::form_fields::kQ, 0); - CPDF_Object* pObj = CPDF_FormField::GetFieldAttr(m_pField->GetDict(), "Q"); + RetainPtr<const CPDF_Object> pObj = + m_pField->GetFieldAttr(pdfium::form_fields::kQ); if (pObj) return pObj->GetInteger(); + return m_pForm->GetFormAlignment(); }
diff --git a/core/fpdfdoc/cpdf_formcontrol.h b/core/fpdfdoc/cpdf_formcontrol.h index d825634..59eec21 100644 --- a/core/fpdfdoc/cpdf_formcontrol.h +++ b/core/fpdfdoc/cpdf_formcontrol.h
@@ -1,4 +1,4 @@ -// Copyright 2016 PDFium Authors. All rights reserved. +// Copyright 2016 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -7,6 +7,7 @@ #ifndef CORE_FPDFDOC_CPDF_FORMCONTROL_H_ #define CORE_FPDFDOC_CPDF_FORMCONTROL_H_ +#include "constants/appearance.h" #include "core/fpdfdoc/cpdf_aaction.h" #include "core/fpdfdoc/cpdf_action.h" #include "core/fpdfdoc/cpdf_annot.h" @@ -18,31 +19,32 @@ #include "core/fxcrt/fx_coordinates.h" #include "core/fxcrt/fx_string.h" #include "core/fxcrt/retain_ptr.h" -#include "core/fxge/fx_dib.h" -#include "third_party/base/optional.h" +#include "core/fxcrt/unowned_ptr.h" +#include "core/fxge/cfx_color.h" +#include "core/fxge/dib/fx_dib.h" +#include "third_party/abseil-cpp/absl/types/optional.h" class CFX_RenderDevice; class CPDF_Dictionary; class CPDF_Font; class CPDF_FormField; class CPDF_InteractiveForm; -class CPDF_OCContext; -class CPDF_RenderOptions; class CPDF_Stream; class CPDF_FormControl { public: - enum HighlightingMode { None = 0, Invert, Outline, Push, Toggle }; + enum HighlightingMode { kNone = 0, kInvert, kOutline, kPush, kToggle }; - CPDF_FormControl(CPDF_FormField* pField, CPDF_Dictionary* pWidgetDict); + CPDF_FormControl(CPDF_FormField* pField, + RetainPtr<CPDF_Dictionary> pWidgetDict, + CPDF_InteractiveForm* pForm); ~CPDF_FormControl(); CPDF_FormField::Type GetType() const { return m_pField->GetType(); } - const CPDF_InteractiveForm* GetInteractiveForm() const { - return m_pForm.Get(); + CPDF_FormField* GetField() const { return m_pField; } + RetainPtr<const CPDF_Dictionary> GetWidgetDict() const { + return m_pWidgetDict; } - CPDF_FormField* GetField() const { return m_pField.Get(); } - CPDF_Dictionary* GetWidget() const { return m_pWidgetDict.Get(); } CFX_FloatRect GetRect() const; ByteString GetCheckedAPState() const; @@ -55,43 +57,42 @@ bool HasMKEntry(const ByteString& csEntry) const; int GetRotation() const; - FX_ARGB GetBorderColor(int& iColorType) { return GetColor(iColorType, "BC"); } + CFX_Color::TypeAndARGB GetColorARGB(const ByteString& csEntry); + float GetOriginalColorComponent(int index, const ByteString& csEntry); - float GetOriginalBorderColor(int index) { - return GetOriginalColor(index, "BC"); + CFX_Color GetOriginalBorderColor() { + return GetOriginalColor(pdfium::appearance::kBC); } - void GetOriginalBorderColor(int& iColorType, float fc[4]) { - GetOriginalColor(iColorType, fc, "BC"); + CFX_Color GetOriginalBackgroundColor() { + return GetOriginalColor(pdfium::appearance::kBG); } - FX_ARGB GetBackgroundColor(int& iColorType) { - return GetColor(iColorType, "BG"); + WideString GetNormalCaption() const { + return GetCaption(pdfium::appearance::kCA); + } + WideString GetRolloverCaption() const { + return GetCaption(pdfium::appearance::kRC); + } + WideString GetDownCaption() const { + return GetCaption(pdfium::appearance::kAC); } - float GetOriginalBackgroundColor(int index) { - return GetOriginalColor(index, "BG"); + RetainPtr<CPDF_Stream> GetNormalIcon() { + return GetIcon(pdfium::appearance::kI); } - - void GetOriginalBackgroundColor(int& iColorType, float fc[4]) { - GetOriginalColor(iColorType, fc, "BG"); + RetainPtr<CPDF_Stream> GetRolloverIcon() { + return GetIcon(pdfium::appearance::kRI); } - - WideString GetNormalCaption() const { return GetCaption("CA"); } - WideString GetRolloverCaption() const { return GetCaption("RC"); } - WideString GetDownCaption() const { return GetCaption("AC"); } - - CPDF_Stream* GetNormalIcon() { return GetIcon("I"); } - CPDF_Stream* GetRolloverIcon() { return GetIcon("RI"); } - CPDF_Stream* GetDownIcon() { return GetIcon("IX"); } + RetainPtr<CPDF_Stream> GetDownIcon() { + return GetIcon(pdfium::appearance::kIX); + } CPDF_IconFit GetIconFit() const; int GetTextPosition() const; - CPDF_Action GetAction() const; - CPDF_AAction GetAdditionalAction() const; CPDF_DefaultAppearance GetDefaultAppearance() const; - Optional<WideString> GetDefaultControlFontName() const; + absl::optional<WideString> GetDefaultControlFontName() const; int GetControlAlignment() const; ByteString GetOnStateName() const; @@ -99,14 +100,10 @@ private: RetainPtr<CPDF_Font> GetDefaultControlFont() const; - FX_ARGB GetColor(int& iColorType, const ByteString& csEntry); - float GetOriginalColor(int index, const ByteString& csEntry); - void GetOriginalColor(int& iColorType, - float fc[4], - const ByteString& csEntry); + CFX_Color GetOriginalColor(const ByteString& csEntry); WideString GetCaption(const ByteString& csEntry) const; - CPDF_Stream* GetIcon(const ByteString& csEntry); + RetainPtr<CPDF_Stream> GetIcon(const ByteString& csEntry); CPDF_ApSettings GetMK() const; UnownedPtr<CPDF_FormField> const m_pField;
diff --git a/core/fpdfdoc/cpdf_formfield.cpp b/core/fpdfdoc/cpdf_formfield.cpp index 1eae005..705827d 100644 --- a/core/fpdfdoc/cpdf_formfield.cpp +++ b/core/fpdfdoc/cpdf_formfield.cpp
@@ -1,4 +1,4 @@ -// Copyright 2014 PDFium Authors. All rights reserved. +// Copyright 2014 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -6,7 +6,7 @@ #include "core/fpdfdoc/cpdf_formfield.h" -#include <memory> +#include <map> #include <set> #include <utility> @@ -17,66 +17,71 @@ #include "core/fpdfapi/parser/cfdf_document.h" #include "core/fpdfapi/parser/cpdf_array.h" #include "core/fpdfapi/parser/cpdf_dictionary.h" -#include "core/fpdfapi/parser/cpdf_document.h" #include "core/fpdfapi/parser/cpdf_name.h" #include "core/fpdfapi/parser/cpdf_number.h" +#include "core/fpdfapi/parser/cpdf_stream.h" #include "core/fpdfapi/parser/cpdf_string.h" #include "core/fpdfapi/parser/fpdf_parser_decode.h" #include "core/fpdfapi/parser/fpdf_parser_utility.h" #include "core/fpdfdoc/cpdf_defaultappearance.h" #include "core/fpdfdoc/cpdf_formcontrol.h" +#include "core/fpdfdoc/cpdf_generateap.h" #include "core/fpdfdoc/cpdf_interactiveform.h" -#include "core/fpdfdoc/cpvt_generateap.h" -#include "third_party/base/ptr_util.h" -#include "third_party/base/stl_util.h" +#include "core/fxcrt/stl_util.h" +#include "third_party/base/check.h" +#include "third_party/base/containers/contains.h" namespace { -const CPDF_Object* GetFieldAttrRecursive(const CPDF_Dictionary* pFieldDict, - const ByteString& name, - int nLevel) { +RetainPtr<const CPDF_Object> GetFieldAttrRecursive( + const CPDF_Dictionary* pFieldDict, + const ByteString& name, + int nLevel) { static constexpr int kGetFieldMaxRecursion = 32; if (!pFieldDict || nLevel > kGetFieldMaxRecursion) return nullptr; - const CPDF_Object* pAttr = pFieldDict->GetDirectObjectFor(name); + RetainPtr<const CPDF_Object> pAttr = pFieldDict->GetDirectObjectFor(name); if (pAttr) return pAttr; return GetFieldAttrRecursive( - pFieldDict->GetDictFor(pdfium::form_fields::kParent), name, nLevel + 1); + pFieldDict->GetDictFor(pdfium::form_fields::kParent).Get(), name, + nLevel + 1); } } // namespace // static -Optional<FormFieldType> CPDF_FormField::IntToFormFieldType(int value) { +absl::optional<FormFieldType> CPDF_FormField::IntToFormFieldType(int value) { if (value >= static_cast<int>(FormFieldType::kUnknown) && value < static_cast<int>(kFormFieldTypeCount)) { - return {static_cast<FormFieldType>(value)}; + return static_cast<FormFieldType>(value); } - return {}; + return absl::nullopt; } // static -const CPDF_Object* CPDF_FormField::GetFieldAttr( +RetainPtr<const CPDF_Object> CPDF_FormField::GetFieldAttrForDict( const CPDF_Dictionary* pFieldDict, const ByteString& name) { return GetFieldAttrRecursive(pFieldDict, name, 0); } // static -CPDF_Object* CPDF_FormField::GetFieldAttr(CPDF_Dictionary* pFieldDict, - const ByteString& name) { - return const_cast<CPDF_Object*>(GetFieldAttrRecursive( - static_cast<const CPDF_Dictionary*>(pFieldDict), name, 0)); +RetainPtr<CPDF_Object> CPDF_FormField::GetMutableFieldAttrForDict( + CPDF_Dictionary* pFieldDict, + const ByteString& name) { + return pdfium::WrapRetain(const_cast<CPDF_Object*>( + GetFieldAttrRecursive(pFieldDict, name, 0).Get())); } // static -WideString CPDF_FormField::GetFullNameForDict(CPDF_Dictionary* pFieldDict) { +WideString CPDF_FormField::GetFullNameForDict( + const CPDF_Dictionary* pFieldDict) { WideString full_name; - std::set<CPDF_Dictionary*> visited; - CPDF_Dictionary* pLevel = pFieldDict; + std::set<const CPDF_Dictionary*> visited; + const CPDF_Dictionary* pLevel = pFieldDict; while (pLevel) { visited.insert(pLevel); WideString short_name = pLevel->GetUnicodeTextFor(pdfium::form_fields::kT); @@ -86,24 +91,24 @@ else full_name = short_name + L'.' + full_name; } - pLevel = pLevel->GetDictFor(pdfium::form_fields::kParent); - if (pdfium::ContainsKey(visited, pLevel)) + pLevel = pLevel->GetDictFor(pdfium::form_fields::kParent).Get(); + if (pdfium::Contains(visited, pLevel)) break; } return full_name; } CPDF_FormField::CPDF_FormField(CPDF_InteractiveForm* pForm, - CPDF_Dictionary* pDict) - : m_pForm(pForm), m_pDict(pDict) { + RetainPtr<CPDF_Dictionary> pDict) + : m_pForm(pForm), m_pDict(std::move(pDict)) { InitFieldFlags(); } CPDF_FormField::~CPDF_FormField() = default; void CPDF_FormField::InitFieldFlags() { - const CPDF_Object* ft_attr = - GetFieldAttr(m_pDict.Get(), pdfium::form_fields::kFT); + RetainPtr<const CPDF_Object> ft_attr = + GetFieldAttrInternal(pdfium::form_fields::kFT); ByteString type_name = ft_attr ? ft_attr->GetString() : ByteString(); uint32_t flags = GetFieldFlags(); m_bRequired = flags & pdfium::form_flags::kRequired; @@ -126,7 +131,6 @@ m_Type = kRichText; else m_Type = kText; - LoadDA(); } else if (type_name == pdfium::form_fields::kCh) { if (flags & pdfium::form_flags::kChoiceCombo) { m_Type = kComboBox; @@ -134,7 +138,7 @@ m_Type = kListBox; m_bIsMultiSelectListBox = flags & pdfium::form_flags::kChoiceMultiSelect; } - LoadDA(); + m_bUseSelectedIndices = UseSelectedIndicesObject(); } else if (type_name == pdfium::form_fields::kSig) { m_Type = kSign; } @@ -144,7 +148,16 @@ return GetFullNameForDict(m_pDict.Get()); } -bool CPDF_FormField::ResetField(NotificationOption notify) { +RetainPtr<const CPDF_Object> CPDF_FormField::GetFieldAttr( + const ByteString& name) const { + return GetFieldAttrInternal(name); +} + +RetainPtr<const CPDF_Dictionary> CPDF_FormField::GetFieldDict() const { + return pdfium::WrapRetain(GetFieldDictInternal()); +} + +bool CPDF_FormField::ResetField() { switch (m_Type) { case kCheckBox: case kRadioButton: { @@ -155,8 +168,7 @@ CheckControl(i, GetControl(i)->IsDefaultChecked(), NotificationOption::kDoNotNotify); } - if (notify == NotificationOption::kNotify && m_pForm->GetFormNotify()) - m_pForm->GetFormNotify()->AfterCheckedStatusChange(this); + m_pForm->NotifyAfterCheckedStatusChange(this); break; } case kComboBox: @@ -166,55 +178,57 @@ int iIndex = GetDefaultSelectedItem(); if (iIndex >= 0) csValue = GetOptionLabel(iIndex); - if (notify == NotificationOption::kNotify && - !NotifyListOrComboBoxBeforeChange(csValue)) { + if (!NotifyListOrComboBoxBeforeChange(csValue)) { return false; } - SetItemSelection(iIndex, true, NotificationOption::kDoNotNotify); - if (notify == NotificationOption::kNotify) - NotifyListOrComboBoxAfterChange(); + SetItemSelection(iIndex, NotificationOption::kDoNotNotify); + NotifyListOrComboBoxAfterChange(); break; } case kText: case kRichText: case kFile: default: { - const CPDF_Object* pDV = GetDefaultValueObject(); WideString csDValue; - if (pDV) - csDValue = pDV->GetUnicodeText(); - WideString csValue; { - // Limit the scope of |pV| because it may get invalidated below. - const CPDF_Object* pV = GetValueObject(); + // Limit scope of |pDV| and |pV| because they may get invalidated + // during notification below. + RetainPtr<const CPDF_Object> pDV = GetDefaultValueObject(); + if (pDV) + csDValue = pDV->GetUnicodeText(); + + RetainPtr<const CPDF_Object> pV = GetValueObject(); if (pV) csValue = pV->GetUnicodeText(); } - bool bHasRV = !!GetFieldAttr(m_pDict.Get(), "RV"); + bool bHasRV = !!GetFieldAttrInternal(pdfium::form_fields::kRV); if (!bHasRV && (csDValue == csValue)) return false; - if (notify == NotificationOption::kNotify && - !NotifyBeforeValueChange(csDValue)) { + if (!m_pForm->NotifyBeforeValueChange(this, csDValue)) return false; - } - if (pDV) { - RetainPtr<CPDF_Object> pClone = pDV->Clone(); - if (!pClone) - return false; - m_pDict->SetFor(pdfium::form_fields::kV, std::move(pClone)); - if (bHasRV) { - m_pDict->SetFor("RV", pDV->Clone()); + { + // Limit scope of |pDV| because it may get invalidated during + // notification below. + RetainPtr<const CPDF_Object> pDV = GetDefaultValueObject(); + if (pDV) { + RetainPtr<CPDF_Object> pClone = pDV->Clone(); + if (!pClone) + return false; + + m_pDict->SetFor(pdfium::form_fields::kV, std::move(pClone)); + if (bHasRV) { + m_pDict->SetFor(pdfium::form_fields::kRV, pDV->Clone()); + } + } else { + m_pDict->RemoveFor(pdfium::form_fields::kV); + m_pDict->RemoveFor(pdfium::form_fields::kRV); } - } else { - m_pDict->RemoveFor(pdfium::form_fields::kV); - m_pDict->RemoveFor("RV"); } - if (notify == NotificationOption::kNotify) - NotifyAfterValueChange(); + m_pForm->NotifyAfterValueChange(this); break; } } @@ -222,11 +236,11 @@ } int CPDF_FormField::CountControls() const { - return pdfium::CollectionSize<int>(GetControls()); + return fxcrt::CollectionSize<int>(GetControls()); } CPDF_FormControl* CPDF_FormField::GetControl(int index) const { - return GetControls()[index].Get(); + return GetControls()[index]; } int CPDF_FormField::GetControlIndex(const CPDF_FormControl* pControl) const { @@ -235,7 +249,10 @@ const auto& controls = GetControls(); auto it = std::find(controls.begin(), controls.end(), pControl); - return it != controls.end() ? it - controls.begin() : -1; + if (it == controls.end()) + return -1; + + return pdfium::base::checked_cast<int>(it - controls.begin()); } FormFieldType CPDF_FormField::GetFieldType() const { @@ -262,42 +279,39 @@ } CPDF_AAction CPDF_FormField::GetAdditionalAction() const { - CPDF_Object* pObj = GetFieldAttr(m_pDict.Get(), pdfium::form_fields::kAA); + RetainPtr<const CPDF_Object> pObj = + GetFieldAttrInternal(pdfium::form_fields::kAA); return CPDF_AAction(pObj ? pObj->GetDict() : nullptr); } WideString CPDF_FormField::GetAlternateName() const { - const CPDF_Object* pObj = - GetFieldAttr(m_pDict.Get(), pdfium::form_fields::kTU); + RetainPtr<const CPDF_Object> pObj = + GetFieldAttrInternal(pdfium::form_fields::kTU); return pObj ? pObj->GetUnicodeText() : WideString(); } WideString CPDF_FormField::GetMappingName() const { - const CPDF_Object* pObj = - GetFieldAttr(m_pDict.Get(), pdfium::form_fields::kTM); + RetainPtr<const CPDF_Object> pObj = + GetFieldAttrInternal(pdfium::form_fields::kTM); return pObj ? pObj->GetUnicodeText() : WideString(); } uint32_t CPDF_FormField::GetFieldFlags() const { - const CPDF_Object* pObj = - GetFieldAttr(m_pDict.Get(), pdfium::form_fields::kFf); + RetainPtr<const CPDF_Object> pObj = + GetFieldAttrInternal(pdfium::form_fields::kFf); return pObj ? pObj->GetInteger() : 0; } -ByteString CPDF_FormField::GetDefaultStyle() const { - const CPDF_Object* pObj = GetFieldAttr(m_pDict.Get(), "DS"); - return pObj ? pObj->GetString() : ByteString(); -} - -void CPDF_FormField::SetOpt(RetainPtr<CPDF_Object> pOpt) { - m_pDict->SetFor("Opt", std::move(pOpt)); +void CPDF_FormField::SetFieldFlags(uint32_t dwFlags) { + m_pDict->SetNewFor<CPDF_Number>(pdfium::form_fields::kFf, + static_cast<int>(dwFlags)); } WideString CPDF_FormField::GetValue(bool bDefault) const { if (GetType() == kCheckBox || GetType() == kRadioButton) return GetCheckValue(bDefault); - const CPDF_Object* pValue = + RetainPtr<const CPDF_Object> pValue = bDefault ? GetDefaultValueObject() : GetValueObject(); if (!pValue) { if (!bDefault && m_Type != kText) @@ -310,11 +324,13 @@ case CPDF_Object::kString: case CPDF_Object::kStream: return pValue->GetUnicodeText(); - case CPDF_Object::kArray: - pValue = pValue->AsArray()->GetDirectObjectAt(0); - if (pValue) - return pValue->GetUnicodeText(); + case CPDF_Object::kArray: { + RetainPtr<const CPDF_Object> pNewValue = + pValue->AsArray()->GetDirectObjectAt(0); + if (pNewValue) + return pNewValue->GetUnicodeText(); break; + } default: break; } @@ -344,26 +360,27 @@ case kComboBox: { WideString csValue = value; if (notify == NotificationOption::kNotify && - !NotifyBeforeValueChange(csValue)) { + !m_pForm->NotifyBeforeValueChange(this, csValue)) { return false; } ByteString key(bDefault ? pdfium::form_fields::kDV : pdfium::form_fields::kV); - m_pDict->SetNewFor<CPDF_String>(key, csValue); + m_pDict->SetNewFor<CPDF_String>(key, csValue.AsStringView()); int iIndex = FindOption(csValue); if (iIndex < 0) { if (m_Type == kRichText && !bDefault) { - m_pDict->SetFor("RV", m_pDict->GetObjectFor(key)->Clone()); + m_pDict->SetFor(pdfium::form_fields::kRV, + m_pDict->GetObjectFor(key)->Clone()); } m_pDict->RemoveFor("I"); } else { if (!bDefault) { ClearSelection(NotificationOption::kDoNotNotify); - SetItemSelection(iIndex, true, NotificationOption::kDoNotNotify); + SetItemSelection(iIndex, NotificationOption::kDoNotNotify); } } if (notify == NotificationOption::kNotify) - NotifyAfterValueChange(); + m_pForm->NotifyAfterValueChange(this); break; } case kListBox: { @@ -375,15 +392,15 @@ return false; if (notify == NotificationOption::kNotify && - !NotifyBeforeSelectionChange(value)) { + !m_pForm->NotifyBeforeSelectionChange(this, value)) { return false; } if (!bDefault) { ClearSelection(NotificationOption::kDoNotNotify); - SetItemSelection(iIndex, true, NotificationOption::kDoNotNotify); + SetItemSelection(iIndex, NotificationOption::kDoNotNotify); } if (notify == NotificationOption::kNotify) - NotifyAfterSelectionChange(); + m_pForm->NotifyAfterSelectionChange(this); break; } default: @@ -398,14 +415,15 @@ } int CPDF_FormField::GetMaxLen() const { - if (const CPDF_Object* pObj = GetFieldAttr(m_pDict.Get(), "MaxLen")) + RetainPtr<const CPDF_Object> pObj = GetFieldAttrInternal("MaxLen"); + if (pObj) return pObj->GetInteger(); for (auto& pControl : GetControls()) { if (!pControl) continue; - const CPDF_Dictionary* pWidgetDict = pControl->GetWidget(); + RetainPtr<const CPDF_Dictionary> pWidgetDict = pControl->GetWidgetDict(); if (pWidgetDict->KeyExist("MaxLen")) return pWidgetDict->GetIntegerFor("MaxLen"); } @@ -420,7 +438,7 @@ if (pValue->IsString() || pValue->IsNumber()) return pValue->GetString().IsEmpty() ? 0 : 1; const CPDF_Array* pArray = pValue->AsArray(); - return pArray ? pArray->size() : 0; + return pArray ? fxcrt::CollectionSize<int>(*pArray) : 0; } int CPDF_FormField::GetSelectedIndex(int index) const { @@ -441,7 +459,8 @@ if (!pArray || index < 0) return -1; - const CPDF_Object* elementValue = pArray->GetDirectObjectAt(index); + RetainPtr<const CPDF_Object> elementValue = + pArray->GetDirectObjectAt(index); sel_value = elementValue ? elementValue->GetUnicodeText() : WideString(); } if (index < CountSelectedOptions()) { @@ -458,7 +477,7 @@ } bool CPDF_FormField::ClearSelection(NotificationOption notify) { - if (notify == NotificationOption::kNotify && m_pForm->GetFormNotify()) { + if (notify == NotificationOption::kNotify) { WideString csValue; int iIndex = GetSelectedIndex(0); if (iIndex >= 0) @@ -474,43 +493,17 @@ } bool CPDF_FormField::IsItemSelected(int index) const { - ASSERT(GetType() == kComboBox || GetType() == kListBox); + DCHECK(GetType() == kComboBox || GetType() == kListBox); if (index < 0 || index >= CountOptions()) return false; - if (IsOptionSelected(index)) - return true; - WideString opt_value = GetOptionValue(index); - const CPDF_Object* pValue = GetValueOrSelectedIndicesObject(); - if (!pValue) - return false; - - if (pValue->IsString()) - return pValue->GetUnicodeText() == opt_value; - - if (pValue->IsNumber()) { - if (pValue->GetString().IsEmpty()) - return false; - return (pValue->GetInteger() == index); - } - - const CPDF_Array* pArray = pValue->AsArray(); - if (!pArray) - return false; - - for (int i = 0; i < CountSelectedOptions(); ++i) { - if (GetSelectedOptionIndex(i) == index) { - const CPDF_Object* pDirectObj = pArray->GetDirectObjectAt(i); - return pDirectObj && pDirectObj->GetUnicodeText() == opt_value; - } - } - return false; + // First consider the /I entry if it is valid, then fall back to the /V entry. + return m_bUseSelectedIndices ? IsSelectedIndex(index) + : IsSelectedOption(GetOptionValue(index)); } -bool CPDF_FormField::SetItemSelection(int index, - bool bSelected, - NotificationOption notify) { - ASSERT(GetType() == kComboBox || GetType() == kListBox); +bool CPDF_FormField::SetItemSelection(int index, NotificationOption notify) { + DCHECK(GetType() == kComboBox || GetType() == kListBox); if (index < 0 || index >= CountOptions()) return false; @@ -520,10 +513,12 @@ return false; } - if (bSelected) - SetItemSelectionSelected(index, opt_value); - else - SetItemSelectionUnselected(index, opt_value); + SetItemSelectionSelected(index, opt_value); + + // UseSelectedIndicesObject() has a non-trivial linearithmic run-time, so run + // only if necessary. + if (!m_bUseSelectedIndices) + m_bUseSelectedIndices = UseSelectedIndicesObject(); if (notify == NotificationOption::kNotify) NotifyListOrComboBoxAfterChange(); @@ -533,69 +528,30 @@ void CPDF_FormField::SetItemSelectionSelected(int index, const WideString& opt_value) { if (GetType() != kListBox) { - m_pDict->SetNewFor<CPDF_String>(pdfium::form_fields::kV, opt_value); - CPDF_Array* pI = m_pDict->SetNewFor<CPDF_Array>("I"); - pI->AddNew<CPDF_Number>(index); + m_pDict->SetNewFor<CPDF_String>(pdfium::form_fields::kV, + opt_value.AsStringView()); + auto pI = m_pDict->SetNewFor<CPDF_Array>("I"); + pI->AppendNew<CPDF_Number>(index); return; } - SelectOption(index, true, NotificationOption::kDoNotNotify); + SelectOption(index); if (!m_bIsMultiSelectListBox) { - m_pDict->SetNewFor<CPDF_String>(pdfium::form_fields::kV, opt_value); + m_pDict->SetNewFor<CPDF_String>(pdfium::form_fields::kV, + opt_value.AsStringView()); return; } - CPDF_Array* pArray = m_pDict->SetNewFor<CPDF_Array>(pdfium::form_fields::kV); + auto pArray = m_pDict->SetNewFor<CPDF_Array>(pdfium::form_fields::kV); for (int i = 0; i < CountOptions(); i++) { if (i == index || IsItemSelected(i)) - pArray->AddNew<CPDF_String>(GetOptionValue(i)); + pArray->AppendNew<CPDF_String>(GetOptionValue(i).AsStringView()); } } -void CPDF_FormField::SetItemSelectionUnselected(int index, - const WideString& opt_value) { - const CPDF_Object* pValue = GetValueObject(); - if (!pValue) - return; - - if (GetType() != kListBox) { - m_pDict->RemoveFor(pdfium::form_fields::kV); - m_pDict->RemoveFor("I"); - return; - } - - SelectOption(index, false, NotificationOption::kDoNotNotify); - if (pValue->IsString()) { - if (pValue->GetUnicodeText() == opt_value) { - m_pDict->RemoveFor(pdfium::form_fields::kV); - } - return; - } - - if (!pValue->IsArray()) - return; - - auto pArray = pdfium::MakeRetain<CPDF_Array>(); - for (int i = 0; i < CountOptions(); i++) { - if (i != index && IsItemSelected(i)) - pArray->AddNew<CPDF_String>(GetOptionValue(i)); - } - if (pArray->size() > 0) { - m_pDict->SetFor(pdfium::form_fields::kV, pArray); - } -} - -bool CPDF_FormField::IsItemDefaultSelected(int index) const { - ASSERT(GetType() == kComboBox || GetType() == kListBox); - if (index < 0 || index >= CountOptions()) - return false; - int iDVIndex = GetDefaultSelectedItem(); - return iDVIndex >= 0 && iDVIndex == index; -} - int CPDF_FormField::GetDefaultSelectedItem() const { - ASSERT(GetType() == kComboBox || GetType() == kListBox); - const CPDF_Object* pValue = GetDefaultValueObject(); + DCHECK(GetType() == kComboBox || GetType() == kListBox); + RetainPtr<const CPDF_Object> pValue = GetDefaultValueObject(); if (!pValue) return -1; WideString csDV = pValue->GetUnicodeText(); @@ -609,22 +565,27 @@ } int CPDF_FormField::CountOptions() const { - const CPDF_Array* pArray = ToArray(GetFieldAttr(m_pDict.Get(), "Opt")); - return pArray ? pArray->size() : 0; + RetainPtr<const CPDF_Array> pArray = ToArray(GetFieldAttrInternal("Opt")); + return pArray ? fxcrt::CollectionSize<int>(*pArray) : 0; } WideString CPDF_FormField::GetOptionText(int index, int sub_index) const { - const CPDF_Array* pArray = ToArray(GetFieldAttr(m_pDict.Get(), "Opt")); + RetainPtr<const CPDF_Array> pArray = ToArray(GetFieldAttrInternal("Opt")); if (!pArray) return WideString(); - const CPDF_Object* pOption = pArray->GetDirectObjectAt(index); + RetainPtr<const CPDF_Object> pOption = pArray->GetDirectObjectAt(index); if (!pOption) return WideString(); - if (const CPDF_Array* pOptionArray = pOption->AsArray()) + + const CPDF_Array* pOptionArray = pOption->AsArray(); + if (pOptionArray) pOption = pOptionArray->GetDirectObjectAt(sub_index); - const CPDF_String* pString = ToString(pOption); + if (!pOption) + return WideString(); + + const CPDF_String* pString = pOption->AsString(); return pString ? pString->GetUnicodeText() : WideString(); } @@ -647,7 +608,7 @@ bool CPDF_FormField::CheckControl(int iControlIndex, bool bChecked, NotificationOption notify) { - ASSERT(GetType() == kCheckBox || GetType() == kRadioButton); + DCHECK(GetType() == kCheckBox || GetType() == kRadioButton); CPDF_FormControl* pControl = GetControl(iControlIndex); if (!pControl) return false; @@ -676,9 +637,9 @@ } } - const CPDF_Object* pOpt = GetFieldAttr(m_pDict.Get(), "Opt"); + RetainPtr<const CPDF_Object> pOpt = GetFieldAttrInternal("Opt"); if (!ToArray(pOpt)) { - ByteString csBExport = PDF_EncodeText(csWExport); + ByteString csBExport = PDF_EncodeText(csWExport.AsStringView()); if (bChecked) { m_pDict->SetNewFor<CPDF_Name>(pdfium::form_fields::kV, csBExport); } else { @@ -691,15 +652,15 @@ } } else if (bChecked) { m_pDict->SetNewFor<CPDF_Name>(pdfium::form_fields::kV, - ByteString::Format("%d", iControlIndex)); + ByteString::FormatInteger(iControlIndex)); } - if (notify == NotificationOption::kNotify && m_pForm->GetFormNotify()) - m_pForm->GetFormNotify()->AfterCheckedStatusChange(this); + if (notify == NotificationOption::kNotify) + m_pForm->NotifyAfterCheckedStatusChange(this); return true; } WideString CPDF_FormField::GetCheckValue(bool bDefault) const { - ASSERT(GetType() == kCheckBox || GetType() == kRadioButton); + DCHECK(GetType() == kCheckBox || GetType() == kRadioButton); WideString csExport = L"Off"; int iCount = CountControls(); for (int i = 0; i < iCount; i++) { @@ -717,7 +678,7 @@ bool CPDF_FormField::SetCheckValue(const WideString& value, bool bDefault, NotificationOption notify) { - ASSERT(GetType() == kCheckBox || GetType() == kRadioButton); + DCHECK(GetType() == kCheckBox || GetType() == kRadioButton); int iCount = CountControls(); for (int i = 0; i < iCount; i++) { CPDF_FormControl* pControl = GetControl(i); @@ -730,163 +691,170 @@ if (val) break; } - if (notify == NotificationOption::kNotify && m_pForm->GetFormNotify()) - m_pForm->GetFormNotify()->AfterCheckedStatusChange(this); + if (notify == NotificationOption::kNotify) + m_pForm->NotifyAfterCheckedStatusChange(this); return true; } int CPDF_FormField::GetTopVisibleIndex() const { - const CPDF_Object* pObj = GetFieldAttr(m_pDict.Get(), "TI"); + RetainPtr<const CPDF_Object> pObj = GetFieldAttrInternal("TI"); return pObj ? pObj->GetInteger() : 0; } int CPDF_FormField::CountSelectedOptions() const { - const CPDF_Array* pArray = ToArray(GetSelectedIndicesObject()); - return pArray ? pArray->size() : 0; + RetainPtr<const CPDF_Array> pArray = ToArray(GetSelectedIndicesObject()); + return pArray ? fxcrt::CollectionSize<int>(*pArray) : 0; } int CPDF_FormField::GetSelectedOptionIndex(int index) const { - const CPDF_Array* pArray = ToArray(GetSelectedIndicesObject()); + if (index < 0) + return 0; + + RetainPtr<const CPDF_Array> pArray = ToArray(GetSelectedIndicesObject()); if (!pArray) return -1; - int iCount = pArray->size(); - if (iCount < 0 || index >= iCount) - return -1; - return pArray->GetIntegerAt(index); + return index < fxcrt::CollectionSize<int>(*pArray) + ? pArray->GetIntegerAt(index) + : -1; } -bool CPDF_FormField::IsOptionSelected(int iOptIndex) const { - const CPDF_Array* pArray = ToArray(GetSelectedIndicesObject()); - if (!pArray) +bool CPDF_FormField::IsSelectedOption(const WideString& wsOptValue) const { + RetainPtr<const CPDF_Object> pValueObject = GetValueObject(); + if (!pValueObject) return false; - CPDF_ArrayLocker locker(pArray); - for (const auto& pObj : locker) { - if (pObj->GetInteger() == iOptIndex) - return true; + const CPDF_Array* pValueArray = pValueObject->AsArray(); + if (pValueArray) { + CPDF_ArrayLocker locker(pValueArray); + for (const auto& pObj : locker) { + if (pObj->IsString() && pObj->GetUnicodeText() == wsOptValue) + return true; + } } - return false; + + return pValueObject->IsString() && + pValueObject->GetUnicodeText() == wsOptValue; } -bool CPDF_FormField::SelectOption(int iOptIndex, - bool bSelected, - NotificationOption notify) { - CPDF_Array* pArray = m_pDict->GetArrayFor("I"); - if (!pArray) { - if (!bSelected) - return true; +bool CPDF_FormField::IsSelectedIndex(int iOptIndex) const { + RetainPtr<const CPDF_Object> pSelectedIndicesObject = + GetSelectedIndicesObject(); + if (!pSelectedIndicesObject) + return false; - pArray = m_pDict->SetNewFor<CPDF_Array>("I"); + const CPDF_Array* pSelectedIndicesArray = pSelectedIndicesObject->AsArray(); + if (pSelectedIndicesArray) { + CPDF_ArrayLocker locker(pSelectedIndicesArray); + for (const auto& pObj : locker) { + if (pObj->IsNumber() && pObj->GetInteger() == iOptIndex) + return true; + } } - bool bReturn = false; + return pSelectedIndicesObject->IsNumber() && + pSelectedIndicesObject->GetInteger() == iOptIndex; +} + +void CPDF_FormField::SelectOption(int iOptIndex) { + RetainPtr<CPDF_Array> pArray = m_pDict->GetOrCreateArrayFor("I"); for (size_t i = 0; i < pArray->size(); i++) { int iFind = pArray->GetIntegerAt(i); - if (iFind == iOptIndex) { - if (bSelected) - return true; - - if (notify == NotificationOption::kNotify && m_pForm->GetFormNotify()) { - WideString csValue = GetOptionLabel(iOptIndex); - if (!NotifyListOrComboBoxBeforeChange(csValue)) - return false; - } - pArray->RemoveAt(i); - bReturn = true; - break; - } + if (iFind == iOptIndex) + return; if (iFind > iOptIndex) { - if (!bSelected) - continue; - - if (notify == NotificationOption::kNotify && m_pForm->GetFormNotify()) { - WideString csValue = GetOptionLabel(iOptIndex); - if (!NotifyListOrComboBoxBeforeChange(csValue)) - return false; - } pArray->InsertNewAt<CPDF_Number>(i, iOptIndex); - bReturn = true; - break; + return; } } - if (!bReturn) { - if (bSelected) - pArray->AddNew<CPDF_Number>(iOptIndex); - if (pArray->IsEmpty()) - m_pDict->RemoveFor("I"); + pArray->AppendNew<CPDF_Number>(iOptIndex); +} + +bool CPDF_FormField::UseSelectedIndicesObject() const { + DCHECK(GetType() == kComboBox || GetType() == kListBox); + + RetainPtr<const CPDF_Object> pSelectedIndicesObject = + GetSelectedIndicesObject(); + if (!pSelectedIndicesObject) + return false; + + // If there's not value object, then just use the indices object. + RetainPtr<const CPDF_Object> pValueObject = GetValueObject(); + if (!pValueObject) + return true; + + // Verify that the selected indices object is either an array or a number and + // count the number of indices. + size_t selected_indices_size; + const CPDF_Array* pSelectedIndicesArray = pSelectedIndicesObject->AsArray(); + if (pSelectedIndicesArray) + selected_indices_size = pSelectedIndicesArray->size(); + else if (pSelectedIndicesObject->IsNumber()) + selected_indices_size = 1; + else + return false; + + // Verify that the number of values is equal to |selected_indices_size|. Then, + // count the number of occurrences of each of the distinct values in the + // values object. + std::map<WideString, size_t> values; + const CPDF_Array* pValueArray = pValueObject->AsArray(); + if (pValueArray) { + if (pValueArray->size() != selected_indices_size) + return false; + CPDF_ArrayLocker locker(pValueArray); + for (const auto& pObj : locker) { + if (pObj->IsString()) + values[pObj->GetUnicodeText()]++; + } + } else if (pValueObject->IsString()) { + if (selected_indices_size != 1) + return false; + values[pValueObject->GetUnicodeText()]++; } - if (notify == NotificationOption::kNotify) - NotifyListOrComboBoxAfterChange(); - return true; -} + // Validate each index in the selected indices object. Then, verify that items + // identified by selected indices entry do not differ from those in the values + // entry of the field dictionary. + const int num_options = CountOptions(); + if (pSelectedIndicesArray) { + CPDF_ArrayLocker locker(pSelectedIndicesArray); + for (const auto& pObj : locker) { + if (!pObj->IsNumber()) + return false; -void CPDF_FormField::LoadDA() { - CPDF_Dictionary* pFormDict = m_pForm->GetFormDict(); - if (!pFormDict) - return; + int index = pObj->GetInteger(); + if (index < 0 || index >= num_options) + return false; - ByteString DA; - if (const CPDF_Object* pObj = GetFieldAttr(m_pDict.Get(), "DA")) - DA = pObj->GetString(); + WideString wsOptValue = GetOptionValue(index); + auto it = values.find(wsOptValue); + if (it == values.end()) + return false; - if (DA.IsEmpty()) - DA = pFormDict->GetStringFor("DA"); + it->second--; + if (it->second == 0) + values.erase(it); + } - if (DA.IsEmpty()) - return; + return values.empty(); + } - CPDF_Dictionary* pDR = pFormDict->GetDictFor("DR"); - if (!pDR) - return; + DCHECK(pSelectedIndicesObject->IsNumber()); + int index = pSelectedIndicesObject->GetInteger(); + if (index < 0 || index >= num_options) + return false; - CPDF_Dictionary* pFont = pDR->GetDictFor("Font"); - if (!ValidateFontResourceDict(pFont)) - return; - - CPDF_DefaultAppearance appearance(DA); - Optional<ByteString> font_name = appearance.GetFont(&m_FontSize); - if (!font_name) - return; - - CPDF_Dictionary* pFontDict = pFont->GetDictFor(*font_name); - if (!pFontDict) - return; - - auto* pData = CPDF_DocPageData::FromDocument(m_pForm->GetDocument()); - m_pFont = pData->GetFont(pFontDict); -} - -bool CPDF_FormField::NotifyBeforeSelectionChange(const WideString& value) { - auto* pNotify = m_pForm->GetFormNotify(); - return !pNotify || pNotify->BeforeSelectionChange(this, value); -} - -void CPDF_FormField::NotifyAfterSelectionChange() { - auto* pNotify = m_pForm->GetFormNotify(); - if (pNotify) - pNotify->AfterSelectionChange(this); -} - -bool CPDF_FormField::NotifyBeforeValueChange(const WideString& value) { - auto* pNotify = m_pForm->GetFormNotify(); - return !pNotify || pNotify->BeforeValueChange(this, value); -} - -void CPDF_FormField::NotifyAfterValueChange() { - auto* pNotify = m_pForm->GetFormNotify(); - if (pNotify) - pNotify->AfterValueChange(this); + return pdfium::Contains(values, GetOptionValue(index)); } bool CPDF_FormField::NotifyListOrComboBoxBeforeChange(const WideString& value) { switch (GetType()) { case kListBox: - return NotifyBeforeSelectionChange(value); + return m_pForm->NotifyBeforeSelectionChange(this, value); case kComboBox: - return NotifyBeforeValueChange(value); + return m_pForm->NotifyBeforeValueChange(this, value); default: return true; } @@ -895,32 +863,42 @@ void CPDF_FormField::NotifyListOrComboBoxAfterChange() { switch (GetType()) { case kListBox: - NotifyAfterSelectionChange(); + m_pForm->NotifyAfterSelectionChange(this); break; case kComboBox: - NotifyAfterValueChange(); + m_pForm->NotifyAfterValueChange(this); break; default: break; } } -const CPDF_Object* CPDF_FormField::GetDefaultValueObject() const { - return GetFieldAttr(m_pDict.Get(), pdfium::form_fields::kDV); +RetainPtr<const CPDF_Object> CPDF_FormField::GetFieldAttrInternal( + const ByteString& name) const { + return GetFieldAttrRecursive(m_pDict.Get(), name, 0); } -const CPDF_Object* CPDF_FormField::GetValueObject() const { - return GetFieldAttr(m_pDict.Get(), pdfium::form_fields::kV); +const CPDF_Dictionary* CPDF_FormField::GetFieldDictInternal() const { + return m_pDict.Get(); } -const CPDF_Object* CPDF_FormField::GetSelectedIndicesObject() const { - ASSERT(GetType() == kComboBox || GetType() == kListBox); - return GetFieldAttr(m_pDict.Get(), "I"); +RetainPtr<const CPDF_Object> CPDF_FormField::GetDefaultValueObject() const { + return GetFieldAttrInternal(pdfium::form_fields::kDV); } -const CPDF_Object* CPDF_FormField::GetValueOrSelectedIndicesObject() const { - ASSERT(GetType() == kComboBox || GetType() == kListBox); - const CPDF_Object* pValue = GetValueObject(); +RetainPtr<const CPDF_Object> CPDF_FormField::GetValueObject() const { + return GetFieldAttrInternal(pdfium::form_fields::kV); +} + +RetainPtr<const CPDF_Object> CPDF_FormField::GetSelectedIndicesObject() const { + DCHECK(GetType() == kComboBox || GetType() == kListBox); + return GetFieldAttrInternal("I"); +} + +RetainPtr<const CPDF_Object> CPDF_FormField::GetValueOrSelectedIndicesObject() + const { + DCHECK(GetType() == kComboBox || GetType() == kListBox); + RetainPtr<const CPDF_Object> pValue = GetValueObject(); return pValue ? pValue : GetSelectedIndicesObject(); }
diff --git a/core/fpdfdoc/cpdf_formfield.h b/core/fpdfdoc/cpdf_formfield.h index aa51ddc..e6e4e9b 100644 --- a/core/fpdfdoc/cpdf_formfield.h +++ b/core/fpdfdoc/cpdf_formfield.h
@@ -1,4 +1,4 @@ -// Copyright 2016 PDFium Authors. All rights reserved. +// Copyright 2016 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -7,24 +7,24 @@ #ifndef CORE_FPDFDOC_CPDF_FORMFIELD_H_ #define CORE_FPDFDOC_CPDF_FORMFIELD_H_ -#include <memory> +#include <stddef.h> +#include <stdint.h> + #include <utility> #include <vector> #include "core/fpdfdoc/cpdf_aaction.h" #include "core/fxcrt/fx_string.h" -#include "core/fxcrt/fx_system.h" #include "core/fxcrt/retain_ptr.h" #include "core/fxcrt/unowned_ptr.h" class CPDF_Dictionary; -class CPDF_Font; class CPDF_FormControl; class CPDF_InteractiveForm; class CPDF_Object; class CPDF_String; -enum class NotificationOption { kDoNotNotify = 0, kNotify }; +enum class NotificationOption : bool { kDoNotNotify = false, kNotify = true }; enum class FormFieldType : uint8_t { kUnknown = 0, @@ -69,23 +69,24 @@ kSign }; - CPDF_FormField(CPDF_InteractiveForm* pForm, CPDF_Dictionary* pDict); + CPDF_FormField(CPDF_InteractiveForm* pForm, RetainPtr<CPDF_Dictionary> pDict); ~CPDF_FormField(); - static Optional<FormFieldType> IntToFormFieldType(int value); - - static const CPDF_Object* GetFieldAttr(const CPDF_Dictionary* pFieldDict, - const ByteString& name); - static CPDF_Object* GetFieldAttr(CPDF_Dictionary* pFieldDict, - const ByteString& name); - - static WideString GetFullNameForDict(CPDF_Dictionary* pFieldDict); + static absl::optional<FormFieldType> IntToFormFieldType(int value); + static WideString GetFullNameForDict(const CPDF_Dictionary* pFieldDict); + static RetainPtr<const CPDF_Object> GetFieldAttrForDict( + const CPDF_Dictionary* pFieldDict, + const ByteString& name); + static RetainPtr<CPDF_Object> GetMutableFieldAttrForDict( + CPDF_Dictionary* pFieldDict, + const ByteString& name); WideString GetFullName() const; Type GetType() const { return m_Type; } - CPDF_Dictionary* GetFieldDict() const { return m_pDict.Get(); } - bool ResetField(NotificationOption notify); + RetainPtr<const CPDF_Object> GetFieldAttr(const ByteString& name) const; + RetainPtr<const CPDF_Dictionary> GetFieldDict() const; + bool ResetField(); int CountControls() const; CPDF_FormControl* GetControl(int index) const; @@ -98,7 +99,7 @@ WideString GetMappingName() const; uint32_t GetFieldFlags() const; - ByteString GetDefaultStyle() const; + void SetFieldFlags(uint32_t dwFlags); bool IsRequired() const { return m_bRequired; } bool IsNoExport() const { return m_bNoExport; } @@ -113,9 +114,7 @@ bool ClearSelection(NotificationOption notify); bool IsItemSelected(int index) const; - bool SetItemSelection(int index, bool bSelected, NotificationOption notify); - - bool IsItemDefaultSelected(int index) const; + bool SetItemSelection(int index, NotificationOption notify); int GetDefaultSelectedItem() const; int CountOptions() const; @@ -130,19 +129,16 @@ int GetTopVisibleIndex() const; int CountSelectedOptions() const; int GetSelectedOptionIndex(int index) const; - bool IsOptionSelected(int iOptIndex) const; - bool SelectOption(int iOptIndex, bool bSelected, NotificationOption notify); + bool IsSelectedOption(const WideString& wsOptValue) const; + bool IsSelectedIndex(int iOptIndex) const; + void SelectOption(int iOptIndex); - float GetFontSize() const { return m_FontSize; } - CPDF_Font* GetFont() const { return m_pFont.Get(); } - - CPDF_Dictionary* GetDict() const { return m_pDict.Get(); } - CPDF_InteractiveForm* GetForm() const { return m_pForm.Get(); } + // Verifies if there is a valid selected indicies (/I) object and whether its + // entries are consistent with the value (/V) object. + bool UseSelectedIndicesObject() const; WideString GetCheckValue(bool bDefault) const; - void SetOpt(RetainPtr<CPDF_Object> pOpt); - private: WideString GetValue(bool bDefault) const; bool SetValue(const WideString& value, @@ -156,23 +152,21 @@ bool bDefault, NotificationOption notify); void SetItemSelectionSelected(int index, const WideString& opt_value); - void SetItemSelectionUnselected(int index, const WideString& opt_value); - bool NotifyBeforeSelectionChange(const WideString& value); - void NotifyAfterSelectionChange(); - bool NotifyBeforeValueChange(const WideString& value); - void NotifyAfterValueChange(); bool NotifyListOrComboBoxBeforeChange(const WideString& value); void NotifyListOrComboBoxAfterChange(); - const CPDF_Object* GetDefaultValueObject() const; - const CPDF_Object* GetValueObject() const; + RetainPtr<const CPDF_Object> GetFieldAttrInternal( + const ByteString& name) const; + const CPDF_Dictionary* GetFieldDictInternal() const; + RetainPtr<const CPDF_Object> GetDefaultValueObject() const; + RetainPtr<const CPDF_Object> GetValueObject() const; // For choice fields. - const CPDF_Object* GetSelectedIndicesObject() const; + RetainPtr<const CPDF_Object> GetSelectedIndicesObject() const; // For choice fields. // Value object takes precedence over selected indices object. - const CPDF_Object* GetValueOrSelectedIndicesObject() const; + RetainPtr<const CPDF_Object> GetValueOrSelectedIndicesObject() const; const std::vector<UnownedPtr<CPDF_FormControl>>& GetControls() const; @@ -181,10 +175,9 @@ bool m_bNoExport = false; bool m_bIsMultiSelectListBox = false; bool m_bIsUnison = false; - float m_FontSize = 0; + bool m_bUseSelectedIndices = false; UnownedPtr<CPDF_InteractiveForm> const m_pForm; RetainPtr<CPDF_Dictionary> const m_pDict; - RetainPtr<CPDF_Font> m_pFont; }; #endif // CORE_FPDFDOC_CPDF_FORMFIELD_H_
diff --git a/core/fpdfdoc/cpdf_formfield_unittest.cpp b/core/fpdfdoc/cpdf_formfield_unittest.cpp index ca75891..41b99f5 100644 --- a/core/fpdfdoc/cpdf_formfield_unittest.cpp +++ b/core/fpdfdoc/cpdf_formfield_unittest.cpp
@@ -1,49 +1,335 @@ -// Copyright 2016 PDFium Authors. All rights reserved. +// Copyright 2016 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "core/fpdfdoc/cpdf_formfield.h" +#include <vector> + +#include "constants/form_fields.h" +#include "constants/form_flags.h" +#include "core/fpdfapi/page/cpdf_pagemodule.h" +#include "core/fpdfapi/parser/cpdf_array.h" #include "core/fpdfapi/parser/cpdf_dictionary.h" +#include "core/fpdfapi/parser/cpdf_document.h" #include "core/fpdfapi/parser/cpdf_indirect_object_holder.h" #include "core/fpdfapi/parser/cpdf_name.h" +#include "core/fpdfapi/parser/cpdf_number.h" #include "core/fpdfapi/parser/cpdf_reference.h" +#include "core/fpdfapi/parser/cpdf_string.h" +#include "core/fpdfapi/parser/cpdf_test_document.h" +#include "core/fpdfdoc/cpdf_interactiveform.h" +#include "core/fxcrt/fx_memory.h" #include "testing/gtest/include/gtest/gtest.h" +#include "third_party/base/containers/contains.h" -TEST(cpdf_formfield, GetFullNameForDict) { +namespace { + +// Create and destroys the page module that is necessary when instantiating a +// CPDF_Document. +class ScopedCPDF_PageModule { + public: + FX_STACK_ALLOCATED(); + + ScopedCPDF_PageModule() { CPDF_PageModule::Create(); } + ~ScopedCPDF_PageModule() { CPDF_PageModule::Destroy(); } +}; + +void TestMultiselectFieldDict(RetainPtr<CPDF_Array> opt_array, + RetainPtr<CPDF_Object> values, + RetainPtr<CPDF_Object> selected_indices, + bool expected_use_indices, + const std::vector<int>& expected_indices, + const std::vector<int>& excluded_indices) { + auto form_dict = pdfium::MakeRetain<CPDF_Dictionary>(); + form_dict->SetNewFor<CPDF_Name>("Type", "Annot"); + form_dict->SetNewFor<CPDF_Name>("Subtype", "Widget"); + form_dict->SetNewFor<CPDF_Name>(pdfium::form_fields::kFT, + pdfium::form_fields::kCh); + constexpr int kMuliSelectFlag = pdfium::form_flags::kChoiceMultiSelect; + form_dict->SetNewFor<CPDF_Number>(pdfium::form_fields::kFf, kMuliSelectFlag); + form_dict->SetFor("Opt", opt_array); + form_dict->SetFor(pdfium::form_fields::kV, values); + form_dict->SetFor("I", selected_indices); + + CPDF_TestDocument doc; + CPDF_InteractiveForm form(&doc); + CPDF_FormField form_field(&form, std::move(form_dict)); + EXPECT_EQ(expected_use_indices, form_field.UseSelectedIndicesObject()); + for (int i = 0; i < form_field.CountOptions(); i++) { + const bool expected_selected = pdfium::Contains(expected_indices, i); + EXPECT_EQ(expected_selected, form_field.IsItemSelected(i)); + } + for (int i : excluded_indices) { + EXPECT_FALSE(form_field.IsItemSelected(i)); + } +} + +} // namespace + +TEST(CPDF_FormFieldTest, GetFullNameForDict) { WideString name = CPDF_FormField::GetFullNameForDict(nullptr); EXPECT_TRUE(name.IsEmpty()); CPDF_IndirectObjectHolder obj_holder; - CPDF_Dictionary* root = obj_holder.NewIndirect<CPDF_Dictionary>(); + auto root = obj_holder.NewIndirect<CPDF_Dictionary>(); root->SetNewFor<CPDF_Name>("T", "foo"); - name = CPDF_FormField::GetFullNameForDict(root); + name = CPDF_FormField::GetFullNameForDict(root.Get()); EXPECT_STREQ("foo", name.ToUTF8().c_str()); - CPDF_Dictionary* dict1 = obj_holder.NewIndirect<CPDF_Dictionary>(); + auto dict1 = obj_holder.NewIndirect<CPDF_Dictionary>(); root->SetNewFor<CPDF_Reference>("Parent", &obj_holder, dict1->GetObjNum()); dict1->SetNewFor<CPDF_Name>("T", "bar"); - name = CPDF_FormField::GetFullNameForDict(root); + name = CPDF_FormField::GetFullNameForDict(root.Get()); EXPECT_STREQ("bar.foo", name.ToUTF8().c_str()); - CPDF_Dictionary* dict2 = dict1->SetNewFor<CPDF_Dictionary>("Parent"); - name = CPDF_FormField::GetFullNameForDict(root); + auto dict2 = dict1->SetNewFor<CPDF_Dictionary>("Parent"); + name = CPDF_FormField::GetFullNameForDict(root.Get()); EXPECT_STREQ("bar.foo", name.ToUTF8().c_str()); - CPDF_Dictionary* dict3 = obj_holder.NewIndirect<CPDF_Dictionary>(); + auto dict3 = obj_holder.NewIndirect<CPDF_Dictionary>(); dict2->SetNewFor<CPDF_Reference>("Parent", &obj_holder, dict3->GetObjNum()); dict3->SetNewFor<CPDF_Name>("T", "qux"); - name = CPDF_FormField::GetFullNameForDict(root); + name = CPDF_FormField::GetFullNameForDict(root.Get()); EXPECT_STREQ("qux.bar.foo", name.ToUTF8().c_str()); dict3->SetNewFor<CPDF_Reference>("Parent", &obj_holder, root->GetObjNum()); - name = CPDF_FormField::GetFullNameForDict(root); + name = CPDF_FormField::GetFullNameForDict(root.Get()); EXPECT_STREQ("qux.bar.foo", name.ToUTF8().c_str()); - name = CPDF_FormField::GetFullNameForDict(dict1); + name = CPDF_FormField::GetFullNameForDict(dict1.Get()); EXPECT_STREQ("foo.qux.bar", name.ToUTF8().c_str()); - name = CPDF_FormField::GetFullNameForDict(dict2); + name = CPDF_FormField::GetFullNameForDict(dict2.Get()); EXPECT_STREQ("bar.foo.qux", name.ToUTF8().c_str()); - name = CPDF_FormField::GetFullNameForDict(dict3); + name = CPDF_FormField::GetFullNameForDict(dict3.Get()); EXPECT_STREQ("bar.foo.qux", name.ToUTF8().c_str()); } + +TEST(CPDF_FormFieldTest, IsItemSelected) { + ScopedCPDF_PageModule page_module; + + auto opt_array = pdfium::MakeRetain<CPDF_Array>(); + opt_array->AppendNew<CPDF_String>(L"Alpha"); + opt_array->AppendNew<CPDF_String>(L"Beta"); + opt_array->AppendNew<CPDF_String>(L"Gamma"); + opt_array->AppendNew<CPDF_String>(L"Delta"); + opt_array->AppendNew<CPDF_String>(L"Epsilon"); + + { + // No Values (/V) or Selected Indices (/I) objects. + std::vector<int> expected_indices; + std::vector<int> excluded_indices{-1, 5}; + TestMultiselectFieldDict(opt_array, /*values=*/nullptr, + /*selected_indices=*/nullptr, + /*expected_use_indices=*/false, expected_indices, + excluded_indices); + } + { + // Values (/V) object is just a string. + auto values = pdfium::MakeRetain<CPDF_String>(/*pPool=*/nullptr, L"Gamma"); + std::vector<int> expected_indices{2}; + std::vector<int> excluded_indices{-1, 5}; + TestMultiselectFieldDict(opt_array, values, /*selected_indices=*/nullptr, + /*expected_use_indices=*/false, expected_indices, + excluded_indices); + } + { + // Values (/V) object is just an invalid string. + auto values = pdfium::MakeRetain<CPDF_String>(/*pPool=*/nullptr, L"Omega"); + std::vector<int> expected_indices; + std::vector<int> excluded_indices{-1, 5}; + TestMultiselectFieldDict(opt_array, values, /*selected_indices=*/nullptr, + /*expected_use_indices=*/false, expected_indices, + excluded_indices); + } + { + // Values (/V) object is an array with one object. + auto values = pdfium::MakeRetain<CPDF_Array>(); + values->AppendNew<CPDF_String>(L"Beta"); + std::vector<int> expected_indices{1}; + std::vector<int> excluded_indices{-1, 5}; + TestMultiselectFieldDict(opt_array, values, /*selected_indices=*/nullptr, + /*expected_use_indices=*/false, expected_indices, + excluded_indices); + } + { + // Values (/V) object is an array with one invalid object. + auto values = pdfium::MakeRetain<CPDF_Array>(); + values->AppendNew<CPDF_String>(L"Omega"); + std::vector<int> expected_indices; + std::vector<int> excluded_indices{-1, 5}; + TestMultiselectFieldDict(opt_array, values, /*selected_indices=*/nullptr, + /*expected_use_indices=*/false, expected_indices, + excluded_indices); + } + { + // Values (/V) object is an array with multiple objects. + auto values = pdfium::MakeRetain<CPDF_Array>(); + values->AppendNew<CPDF_String>(L"Beta"); + values->AppendNew<CPDF_String>(L"Epsilon"); + std::vector<int> expected_indices{1, 4}; + std::vector<int> excluded_indices{-1, 5}; + TestMultiselectFieldDict(opt_array, values, /*selected_indices=*/nullptr, + /*expected_use_indices=*/false, expected_indices, + excluded_indices); + } + { + // Values (/V) object is an array with multiple objects with one invalid. + auto values = pdfium::MakeRetain<CPDF_Array>(); + values->AppendNew<CPDF_String>(L"Beta"); + values->AppendNew<CPDF_String>(L"Epsilon"); + values->AppendNew<CPDF_String>(L"Omega"); + std::vector<int> expected_indices{1, 4}; + std::vector<int> excluded_indices{-1, 5}; + TestMultiselectFieldDict(opt_array, values, /*selected_indices=*/nullptr, + /*expected_use_indices=*/false, expected_indices, + excluded_indices); + } + { + // Selected indices (/I) object is just a number. + auto selected_indices = pdfium::MakeRetain<CPDF_Number>(3); + std::vector<int> expected_indices{3}; + std::vector<int> excluded_indices{-1, 5}; + TestMultiselectFieldDict(opt_array, /*values=*/nullptr, selected_indices, + /*expected_use_indices=*/true, expected_indices, + excluded_indices); + } + { + // Selected indices (/I) object is just an invalid number. + auto selected_indices = pdfium::MakeRetain<CPDF_Number>(26); + std::vector<int> expected_indices; + std::vector<int> excluded_indices{-1, 5, 26}; + TestMultiselectFieldDict(opt_array, /*values=*/nullptr, selected_indices, + /*expected_use_indices=*/true, expected_indices, + excluded_indices); + } + { + // Selected indices (/I) object is an array with one object. + auto selected_indices = pdfium::MakeRetain<CPDF_Array>(); + selected_indices->AppendNew<CPDF_Number>(0); + std::vector<int> expected_indices{0}; + std::vector<int> excluded_indices{-1, 5}; + TestMultiselectFieldDict(opt_array, /*values=*/nullptr, selected_indices, + /*expected_use_indices=*/true, expected_indices, + excluded_indices); + } + { + // Selected indices (/I) object is an array with multiple objects. + auto selected_indices = pdfium::MakeRetain<CPDF_Array>(); + selected_indices->AppendNew<CPDF_Number>(0); + selected_indices->AppendNew<CPDF_Number>(2); + selected_indices->AppendNew<CPDF_Number>(3); + std::vector<int> expected_indices{0, 2, 3}; + std::vector<int> excluded_indices{-1, 5}; + TestMultiselectFieldDict(opt_array, /*values=*/nullptr, selected_indices, + /*expected_use_indices=*/true, expected_indices, + excluded_indices); + } + { + // Selected indices (/I) object is an array with multiple objects and some + // are invalid. + auto selected_indices = pdfium::MakeRetain<CPDF_Array>(); + selected_indices->AppendNew<CPDF_Number>(0); + selected_indices->AppendNew<CPDF_Number>(2); + selected_indices->AppendNew<CPDF_Number>(3); + selected_indices->AppendNew<CPDF_Number>(-5); + selected_indices->AppendNew<CPDF_Number>(12); + selected_indices->AppendNew<CPDF_Number>(42); + std::vector<int> expected_indices{0, 2, 3}; + std::vector<int> excluded_indices{-5, -1, 5, 12, 42}; + TestMultiselectFieldDict(opt_array, /*values=*/nullptr, selected_indices, + /*expected_use_indices=*/true, expected_indices, + excluded_indices); + } + { + // Values (/V) or Selected Indices (/I) objects conflict with different + // lengths. + auto values = pdfium::MakeRetain<CPDF_Array>(); + values->AppendNew<CPDF_String>(L"Beta"); + values->AppendNew<CPDF_String>(L"Epsilon"); + auto selected_indices = pdfium::MakeRetain<CPDF_Array>(); + selected_indices->AppendNew<CPDF_Number>(0); + selected_indices->AppendNew<CPDF_Number>(2); + selected_indices->AppendNew<CPDF_Number>(3); + std::vector<int> expected_indices{1, 4}; + std::vector<int> excluded_indices{-1, 5}; + TestMultiselectFieldDict(opt_array, values, selected_indices, + /*expected_use_indices=*/false, expected_indices, + excluded_indices); + } + { + // Values (/V) or Selected Indices (/I) objects conflict with same lengths. + auto values = pdfium::MakeRetain<CPDF_Array>(); + values->AppendNew<CPDF_String>(L"Alpha"); + values->AppendNew<CPDF_String>(L"Epsilon"); + auto selected_indices = pdfium::MakeRetain<CPDF_Array>(); + selected_indices->AppendNew<CPDF_Number>(2); + selected_indices->AppendNew<CPDF_Number>(3); + std::vector<int> expected_indices{0, 4}; + std::vector<int> excluded_indices{-1, 5}; + TestMultiselectFieldDict(opt_array, values, selected_indices, + /*expected_use_indices=*/false, expected_indices, + excluded_indices); + } + { + // Values (/V) or Selected Indices (/I) objects conflict with values being + // invalid. + auto values = pdfium::MakeRetain<CPDF_Array>(); + values->AppendNew<CPDF_String>(L"Beta"); + values->AppendNew<CPDF_String>(L"Epsilon"); + values->AppendNew<CPDF_String>(L"Omega"); + auto selected_indices = pdfium::MakeRetain<CPDF_Array>(); + selected_indices->AppendNew<CPDF_Number>(1); + selected_indices->AppendNew<CPDF_Number>(4); + std::vector<int> expected_indices{1, 4}; + std::vector<int> excluded_indices{-1, 5}; + TestMultiselectFieldDict(opt_array, values, selected_indices, + /*expected_use_indices=*/false, expected_indices, + excluded_indices); + } + { + // Values (/V) or Selected Indices (/I) objects conflict with selected + // indices being invalid. + auto values = pdfium::MakeRetain<CPDF_Array>(); + values->AppendNew<CPDF_String>(L"Beta"); + values->AppendNew<CPDF_String>(L"Epsilon"); + auto selected_indices = pdfium::MakeRetain<CPDF_Array>(); + selected_indices->AppendNew<CPDF_Number>(1); + selected_indices->AppendNew<CPDF_Number>(4); + selected_indices->AppendNew<CPDF_Number>(26); + std::vector<int> expected_indices{1, 4}; + std::vector<int> excluded_indices{-1, 5, 26}; + TestMultiselectFieldDict(opt_array, values, selected_indices, + /*expected_use_indices=*/false, expected_indices, + excluded_indices); + } + { + // Values (/V) or Selected Indices (/I) objects conflict with both being + // invalid. + auto values = pdfium::MakeRetain<CPDF_Array>(); + values->AppendNew<CPDF_String>(L"Beta"); + values->AppendNew<CPDF_String>(L"Epsilon"); + values->AppendNew<CPDF_String>(L"Omega"); + auto selected_indices = pdfium::MakeRetain<CPDF_Array>(); + selected_indices->AppendNew<CPDF_Number>(0); + selected_indices->AppendNew<CPDF_Number>(2); + selected_indices->AppendNew<CPDF_Number>(3); + selected_indices->AppendNew<CPDF_Number>(26); + std::vector<int> expected_indices{1, 4}; + std::vector<int> excluded_indices{-1, 5, 26}; + TestMultiselectFieldDict(opt_array, values, selected_indices, + /*expected_use_indices=*/false, expected_indices, + excluded_indices); + } + { + // Values (/V) or Selected Indices (/I) objects conflict with each not being + // an array. + auto values = pdfium::MakeRetain<CPDF_String>(/*pPool=*/nullptr, L"Gamma"); + auto selected_indices = pdfium::MakeRetain<CPDF_Number>(4); + std::vector<int> expected_indices{2}; + std::vector<int> excluded_indices{-1, 5}; + TestMultiselectFieldDict(opt_array, values, selected_indices, + /*expected_use_indices=*/false, expected_indices, + excluded_indices); + } +}
diff --git a/core/fpdfdoc/cpdf_generateap.cpp b/core/fpdfdoc/cpdf_generateap.cpp new file mode 100644 index 0000000..8c6f25e --- /dev/null +++ b/core/fpdfdoc/cpdf_generateap.cpp
@@ -0,0 +1,1381 @@ +// Copyright 2016 The PDFium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com + +#include "core/fpdfdoc/cpdf_generateap.h" + +#include <algorithm> +#include <sstream> +#include <utility> + +#include "constants/annotation_common.h" +#include "constants/appearance.h" +#include "constants/font_encodings.h" +#include "constants/form_fields.h" +#include "core/fpdfapi/font/cpdf_font.h" +#include "core/fpdfapi/page/cpdf_docpagedata.h" +#include "core/fpdfapi/parser/cpdf_array.h" +#include "core/fpdfapi/parser/cpdf_boolean.h" +#include "core/fpdfapi/parser/cpdf_dictionary.h" +#include "core/fpdfapi/parser/cpdf_document.h" +#include "core/fpdfapi/parser/cpdf_name.h" +#include "core/fpdfapi/parser/cpdf_number.h" +#include "core/fpdfapi/parser/cpdf_reference.h" +#include "core/fpdfapi/parser/cpdf_stream.h" +#include "core/fpdfapi/parser/cpdf_string.h" +#include "core/fpdfapi/parser/fpdf_parser_decode.h" +#include "core/fpdfapi/parser/fpdf_parser_utility.h" +#include "core/fpdfdoc/cpdf_annot.h" +#include "core/fpdfdoc/cpdf_color_utils.h" +#include "core/fpdfdoc/cpdf_defaultappearance.h" +#include "core/fpdfdoc/cpdf_formfield.h" +#include "core/fpdfdoc/cpvt_fontmap.h" +#include "core/fpdfdoc/cpvt_variabletext.h" +#include "core/fpdfdoc/cpvt_word.h" +#include "core/fxcrt/fx_string_wrappers.h" +#include "core/fxge/cfx_renderdevice.h" + +namespace { + +struct CPVT_Dash { + CPVT_Dash(int32_t dash, int32_t gap, int32_t phase) + : nDash(dash), nGap(gap), nPhase(phase) {} + + int32_t nDash; + int32_t nGap; + int32_t nPhase; +}; + +enum class PaintOperation { kStroke, kFill }; + +ByteString GetPDFWordString(IPVT_FontMap* pFontMap, + int32_t nFontIndex, + uint16_t Word, + uint16_t SubWord) { + if (SubWord > 0) + return ByteString::Format("%c", SubWord); + + if (!pFontMap) + return ByteString(); + + RetainPtr<CPDF_Font> pPDFFont = pFontMap->GetPDFFont(nFontIndex); + if (!pPDFFont) + return ByteString(); + + if (pPDFFont->GetBaseFontName() == "Symbol" || + pPDFFont->GetBaseFontName() == "ZapfDingbats") { + return ByteString::Format("%c", Word); + } + + ByteString sWord; + uint32_t dwCharCode = pPDFFont->CharCodeFromUnicode(Word); + if (dwCharCode != CPDF_Font::kInvalidCharCode) + pPDFFont->AppendChar(&sWord, dwCharCode); + + return sWord; +} + +ByteString GetWordRenderString(ByteStringView strWords) { + if (strWords.IsEmpty()) + return ByteString(); + return PDF_EncodeString(strWords) + " Tj\n"; +} + +ByteString GetFontSetString(IPVT_FontMap* pFontMap, + int32_t nFontIndex, + float fFontSize) { + fxcrt::ostringstream sRet; + if (pFontMap) { + ByteString sFontAlias = pFontMap->GetPDFFontAlias(nFontIndex); + if (sFontAlias.GetLength() > 0 && fFontSize > 0) + sRet << "/" << sFontAlias << " " << fFontSize << " Tf\n"; + } + return ByteString(sRet); +} + +ByteString GenerateEditAP(IPVT_FontMap* pFontMap, + CPVT_VariableText::Iterator* pIterator, + const CFX_PointF& ptOffset, + bool bContinuous, + uint16_t SubWord) { + fxcrt::ostringstream sEditStream; + fxcrt::ostringstream sLineStream; + CFX_PointF ptOld; + CFX_PointF ptNew; + int32_t nCurFontIndex = -1; + CPVT_WordPlace oldplace; + ByteString sWords; + pIterator->SetAt(0); + while (pIterator->NextWord()) { + CPVT_WordPlace place = pIterator->GetWordPlace(); + if (bContinuous) { + if (place.LineCmp(oldplace) != 0) { + if (!sWords.IsEmpty()) { + sLineStream << GetWordRenderString(sWords.AsStringView()); + sEditStream << sLineStream.str(); + sLineStream.str(""); + sWords.clear(); + } + CPVT_Word word; + if (pIterator->GetWord(word)) { + ptNew = CFX_PointF(word.ptWord.x + ptOffset.x, + word.ptWord.y + ptOffset.y); + } else { + CPVT_Line line; + pIterator->GetLine(line); + ptNew = CFX_PointF(line.ptLine.x + ptOffset.x, + line.ptLine.y + ptOffset.y); + } + if (ptNew != ptOld) { + sLineStream << ptNew.x - ptOld.x << " " << ptNew.y - ptOld.y + << " Td\n"; + ptOld = ptNew; + } + } + CPVT_Word word; + if (pIterator->GetWord(word)) { + if (word.nFontIndex != nCurFontIndex) { + if (!sWords.IsEmpty()) { + sLineStream << GetWordRenderString(sWords.AsStringView()); + sWords.clear(); + } + sLineStream << GetFontSetString(pFontMap, word.nFontIndex, + word.fFontSize); + nCurFontIndex = word.nFontIndex; + } + sWords += GetPDFWordString(pFontMap, nCurFontIndex, word.Word, SubWord); + } + oldplace = place; + } else { + CPVT_Word word; + if (pIterator->GetWord(word)) { + ptNew = + CFX_PointF(word.ptWord.x + ptOffset.x, word.ptWord.y + ptOffset.y); + if (ptNew != ptOld) { + sEditStream << ptNew.x - ptOld.x << " " << ptNew.y - ptOld.y + << " Td\n"; + ptOld = ptNew; + } + if (word.nFontIndex != nCurFontIndex) { + sEditStream << GetFontSetString(pFontMap, word.nFontIndex, + word.fFontSize); + nCurFontIndex = word.nFontIndex; + } + sEditStream << GetWordRenderString( + GetPDFWordString(pFontMap, nCurFontIndex, word.Word, SubWord) + .AsStringView()); + } + } + } + if (!sWords.IsEmpty()) { + sLineStream << GetWordRenderString(sWords.AsStringView()); + sEditStream << sLineStream.str(); + } + return ByteString(sEditStream); +} + +ByteString GenerateColorAP(const CFX_Color& color, PaintOperation nOperation) { + fxcrt::ostringstream sColorStream; + switch (color.nColorType) { + case CFX_Color::Type::kRGB: + sColorStream << color.fColor1 << " " << color.fColor2 << " " + << color.fColor3 << " " + << (nOperation == PaintOperation::kStroke ? "RG" : "rg") + << "\n"; + break; + case CFX_Color::Type::kGray: + sColorStream << color.fColor1 << " " + << (nOperation == PaintOperation::kStroke ? "G" : "g") + << "\n"; + break; + case CFX_Color::Type::kCMYK: + sColorStream << color.fColor1 << " " << color.fColor2 << " " + << color.fColor3 << " " << color.fColor4 << " " + << (nOperation == PaintOperation::kStroke ? "K" : "k") + << "\n"; + break; + case CFX_Color::Type::kTransparent: + break; + } + return ByteString(sColorStream); +} + +ByteString GenerateBorderAP(const CFX_FloatRect& rect, + float fWidth, + const CFX_Color& color, + const CFX_Color& crLeftTop, + const CFX_Color& crRightBottom, + BorderStyle nStyle, + const CPVT_Dash& dash) { + fxcrt::ostringstream sAppStream; + ByteString sColor; + float fLeft = rect.left; + float fRight = rect.right; + float fTop = rect.top; + float fBottom = rect.bottom; + if (fWidth > 0.0f) { + float fHalfWidth = fWidth / 2.0f; + switch (nStyle) { + default: + case BorderStyle::kSolid: + sColor = GenerateColorAP(color, PaintOperation::kFill); + if (sColor.GetLength() > 0) { + sAppStream << sColor; + sAppStream << fLeft << " " << fBottom << " " << fRight - fLeft << " " + << fTop - fBottom << " re\n"; + sAppStream << fLeft + fWidth << " " << fBottom + fWidth << " " + << fRight - fLeft - fWidth * 2 << " " + << fTop - fBottom - fWidth * 2 << " re\n"; + sAppStream << "f*\n"; + } + break; + case BorderStyle::kDash: + sColor = GenerateColorAP(color, PaintOperation::kStroke); + if (sColor.GetLength() > 0) { + sAppStream << sColor; + sAppStream << fWidth << " w" + << " [" << dash.nDash << " " << dash.nGap << "] " + << dash.nPhase << " d\n"; + sAppStream << fLeft + fWidth / 2 << " " << fBottom + fWidth / 2 + << " m\n"; + sAppStream << fLeft + fWidth / 2 << " " << fTop - fWidth / 2 + << " l\n"; + sAppStream << fRight - fWidth / 2 << " " << fTop - fWidth / 2 + << " l\n"; + sAppStream << fRight - fWidth / 2 << " " << fBottom + fWidth / 2 + << " l\n"; + sAppStream << fLeft + fWidth / 2 << " " << fBottom + fWidth / 2 + << " l S\n"; + } + break; + case BorderStyle::kBeveled: + case BorderStyle::kInset: + sColor = GenerateColorAP(crLeftTop, PaintOperation::kFill); + if (sColor.GetLength() > 0) { + sAppStream << sColor; + sAppStream << fLeft + fHalfWidth << " " << fBottom + fHalfWidth + << " m\n"; + sAppStream << fLeft + fHalfWidth << " " << fTop - fHalfWidth + << " l\n"; + sAppStream << fRight - fHalfWidth << " " << fTop - fHalfWidth + << " l\n"; + sAppStream << fRight - fHalfWidth * 2 << " " << fTop - fHalfWidth * 2 + << " l\n"; + sAppStream << fLeft + fHalfWidth * 2 << " " << fTop - fHalfWidth * 2 + << " l\n"; + sAppStream << fLeft + fHalfWidth * 2 << " " + << fBottom + fHalfWidth * 2 << " l f\n"; + } + sColor = GenerateColorAP(crRightBottom, PaintOperation::kFill); + if (sColor.GetLength() > 0) { + sAppStream << sColor; + sAppStream << fRight - fHalfWidth << " " << fTop - fHalfWidth + << " m\n"; + sAppStream << fRight - fHalfWidth << " " << fBottom + fHalfWidth + << " l\n"; + sAppStream << fLeft + fHalfWidth << " " << fBottom + fHalfWidth + << " l\n"; + sAppStream << fLeft + fHalfWidth * 2 << " " + << fBottom + fHalfWidth * 2 << " l\n"; + sAppStream << fRight - fHalfWidth * 2 << " " + << fBottom + fHalfWidth * 2 << " l\n"; + sAppStream << fRight - fHalfWidth * 2 << " " << fTop - fHalfWidth * 2 + << " l f\n"; + } + sColor = GenerateColorAP(color, PaintOperation::kFill); + if (sColor.GetLength() > 0) { + sAppStream << sColor; + sAppStream << fLeft << " " << fBottom << " " << fRight - fLeft << " " + << fTop - fBottom << " re\n"; + sAppStream << fLeft + fHalfWidth << " " << fBottom + fHalfWidth << " " + << fRight - fLeft - fHalfWidth * 2 << " " + << fTop - fBottom - fHalfWidth * 2 << " re f*\n"; + } + break; + case BorderStyle::kUnderline: + sColor = GenerateColorAP(color, PaintOperation::kStroke); + if (sColor.GetLength() > 0) { + sAppStream << sColor; + sAppStream << fWidth << " w\n"; + sAppStream << fLeft << " " << fBottom + fWidth / 2 << " m\n"; + sAppStream << fRight << " " << fBottom + fWidth / 2 << " l S\n"; + } + break; + } + } + return ByteString(sAppStream); +} + +ByteString GetColorStringWithDefault(const CPDF_Array* pColor, + const CFX_Color& crDefaultColor, + PaintOperation nOperation) { + if (pColor) { + CFX_Color color = fpdfdoc::CFXColorFromArray(*pColor); + return GenerateColorAP(color, nOperation); + } + + return GenerateColorAP(crDefaultColor, nOperation); +} + +float GetBorderWidth(const CPDF_Dictionary* pDict) { + RetainPtr<const CPDF_Dictionary> pBorderStyleDict = pDict->GetDictFor("BS"); + if (pBorderStyleDict && pBorderStyleDict->KeyExist("W")) + return pBorderStyleDict->GetFloatFor("W"); + + auto pBorderArray = pDict->GetArrayFor(pdfium::annotation::kBorder); + if (pBorderArray && pBorderArray->size() > 2) + return pBorderArray->GetFloatAt(2); + + return 1; +} + +RetainPtr<const CPDF_Array> GetDashArray(const CPDF_Dictionary* pDict) { + RetainPtr<const CPDF_Dictionary> pBorderStyleDict = pDict->GetDictFor("BS"); + if (pBorderStyleDict && pBorderStyleDict->GetByteStringFor("S") == "D") + return pBorderStyleDict->GetArrayFor("D"); + + RetainPtr<const CPDF_Array> pBorderArray = + pDict->GetArrayFor(pdfium::annotation::kBorder); + if (pBorderArray && pBorderArray->size() == 4) + return pBorderArray->GetArrayAt(3); + + return nullptr; +} + +ByteString GetDashPatternString(const CPDF_Dictionary* pDict) { + RetainPtr<const CPDF_Array> pDashArray = GetDashArray(pDict); + if (!pDashArray || pDashArray->IsEmpty()) + return ByteString(); + + // Support maximum of ten elements in the dash array. + size_t pDashArrayCount = std::min<size_t>(pDashArray->size(), 10); + fxcrt::ostringstream sDashStream; + + sDashStream << "["; + for (size_t i = 0; i < pDashArrayCount; ++i) + sDashStream << pDashArray->GetFloatAt(i) << " "; + sDashStream << "] 0 d\n"; + + return ByteString(sDashStream); +} + +ByteString GetPopupContentsString(CPDF_Document* pDoc, + const CPDF_Dictionary& pAnnotDict, + RetainPtr<CPDF_Font> pDefFont, + const ByteString& sFontName) { + WideString swValue(pAnnotDict.GetUnicodeTextFor(pdfium::form_fields::kT)); + swValue += L'\n'; + swValue += pAnnotDict.GetUnicodeTextFor(pdfium::annotation::kContents); + + CPVT_FontMap map(pDoc, nullptr, std::move(pDefFont), sFontName); + CPVT_VariableText::Provider prd(&map); + CPVT_VariableText vt(&prd); + vt.SetPlateRect(pAnnotDict.GetRectFor(pdfium::annotation::kRect)); + vt.SetFontSize(12); + vt.SetAutoReturn(true); + vt.SetMultiLine(true); + vt.Initialize(); + vt.SetText(swValue); + vt.RearrangeAll(); + + CFX_PointF ptOffset(3.0f, -3.0f); + ByteString sContent = + GenerateEditAP(&map, vt.GetIterator(), ptOffset, false, 0); + + if (sContent.IsEmpty()) + return ByteString(); + + ByteString sColorAP = GenerateColorAP( + CFX_Color(CFX_Color::Type::kRGB, 0, 0, 0), PaintOperation::kFill); + + return ByteString{"BT\n", sColorAP.AsStringView(), sContent.AsStringView(), + "ET\n", "Q\n"}; +} + +RetainPtr<CPDF_Dictionary> GenerateResourceFontDict( + CPDF_Document* pDoc, + const ByteString& sFontDictName) { + auto pFontDict = pDoc->NewIndirect<CPDF_Dictionary>(); + pFontDict->SetNewFor<CPDF_Name>("Type", "Font"); + pFontDict->SetNewFor<CPDF_Name>("Subtype", "Type1"); + pFontDict->SetNewFor<CPDF_Name>("BaseFont", CFX_Font::kDefaultAnsiFontName); + pFontDict->SetNewFor<CPDF_Name>("Encoding", + pdfium::font_encodings::kWinAnsiEncoding); + + auto pResourceFontDict = pDoc->New<CPDF_Dictionary>(); + pResourceFontDict->SetNewFor<CPDF_Reference>(sFontDictName, pDoc, + pFontDict->GetObjNum()); + return pResourceFontDict; +} + +ByteString GetPaintOperatorString(bool bIsStrokeRect, bool bIsFillRect) { + if (bIsStrokeRect) + return bIsFillRect ? "b" : "s"; + return bIsFillRect ? "f" : "n"; +} + +ByteString GenerateTextSymbolAP(const CFX_FloatRect& rect) { + fxcrt::ostringstream sAppStream; + sAppStream << GenerateColorAP(CFX_Color(CFX_Color::Type::kRGB, 1, 1, 0), + PaintOperation::kFill); + sAppStream << GenerateColorAP(CFX_Color(CFX_Color::Type::kRGB, 0, 0, 0), + PaintOperation::kStroke); + + const float fBorderWidth = 1; + sAppStream << fBorderWidth << " w\n"; + + const float fHalfWidth = fBorderWidth / 2; + const float fTipDelta = 4; + + CFX_FloatRect outerRect1 = rect; + outerRect1.Deflate(fHalfWidth, fHalfWidth); + outerRect1.bottom += fTipDelta; + + CFX_FloatRect outerRect2 = outerRect1; + outerRect2.left += fTipDelta; + outerRect2.right = outerRect2.left + fTipDelta; + outerRect2.top = outerRect2.bottom - fTipDelta; + float outerRect2Middle = (outerRect2.left + outerRect2.right) / 2; + + // Draw outer boxes. + sAppStream << outerRect1.left << " " << outerRect1.bottom << " m\n" + << outerRect1.left << " " << outerRect1.top << " l\n" + << outerRect1.right << " " << outerRect1.top << " l\n" + << outerRect1.right << " " << outerRect1.bottom << " l\n" + << outerRect2.right << " " << outerRect2.bottom << " l\n" + << outerRect2Middle << " " << outerRect2.top << " l\n" + << outerRect2.left << " " << outerRect2.bottom << " l\n" + << outerRect1.left << " " << outerRect1.bottom << " l\n"; + + // Draw inner lines. + CFX_FloatRect lineRect = outerRect1; + const float fXDelta = 2; + const float fYDelta = (lineRect.top - lineRect.bottom) / 4; + + lineRect.left += fXDelta; + lineRect.right -= fXDelta; + for (int i = 0; i < 3; ++i) { + lineRect.top -= fYDelta; + sAppStream << lineRect.left << " " << lineRect.top << " m\n" + << lineRect.right << " " << lineRect.top << " l\n"; + } + sAppStream << "B*\n"; + + return ByteString(sAppStream); +} + +RetainPtr<CPDF_Dictionary> GenerateExtGStateDict( + const CPDF_Dictionary& pAnnotDict, + const ByteString& sExtGSDictName, + const ByteString& sBlendMode) { + auto pGSDict = + pdfium::MakeRetain<CPDF_Dictionary>(pAnnotDict.GetByteStringPool()); + pGSDict->SetNewFor<CPDF_Name>("Type", "ExtGState"); + + float fOpacity = pAnnotDict.KeyExist("CA") ? pAnnotDict.GetFloatFor("CA") : 1; + pGSDict->SetNewFor<CPDF_Number>("CA", fOpacity); + pGSDict->SetNewFor<CPDF_Number>("ca", fOpacity); + pGSDict->SetNewFor<CPDF_Boolean>("AIS", false); + pGSDict->SetNewFor<CPDF_Name>("BM", sBlendMode); + + auto pExtGStateDict = + pdfium::MakeRetain<CPDF_Dictionary>(pAnnotDict.GetByteStringPool()); + pExtGStateDict->SetFor(sExtGSDictName, pGSDict); + return pExtGStateDict; +} + +RetainPtr<CPDF_Dictionary> GenerateResourceDict( + CPDF_Document* pDoc, + RetainPtr<CPDF_Dictionary> pExtGStateDict, + RetainPtr<CPDF_Dictionary> pResourceFontDict) { + auto pResourceDict = pDoc->New<CPDF_Dictionary>(); + if (pExtGStateDict) + pResourceDict->SetFor("ExtGState", pExtGStateDict); + if (pResourceFontDict) + pResourceDict->SetFor("Font", pResourceFontDict); + return pResourceDict; +} + +void GenerateAndSetAPDict(CPDF_Document* pDoc, + CPDF_Dictionary* pAnnotDict, + fxcrt::ostringstream* psAppStream, + RetainPtr<CPDF_Dictionary> pResourceDict, + bool bIsTextMarkupAnnotation) { + auto pNormalStream = pDoc->NewIndirect<CPDF_Stream>(); + pNormalStream->SetDataFromStringstream(psAppStream); + + RetainPtr<CPDF_Dictionary> pAPDict = + pAnnotDict->GetOrCreateDictFor(pdfium::annotation::kAP); + pAPDict->SetNewFor<CPDF_Reference>("N", pDoc, pNormalStream->GetObjNum()); + + RetainPtr<CPDF_Dictionary> pStreamDict = pNormalStream->GetMutableDict(); + pStreamDict->SetNewFor<CPDF_Number>("FormType", 1); + pStreamDict->SetNewFor<CPDF_Name>("Type", "XObject"); + pStreamDict->SetNewFor<CPDF_Name>("Subtype", "Form"); + pStreamDict->SetMatrixFor("Matrix", CFX_Matrix()); + + CFX_FloatRect rect = bIsTextMarkupAnnotation + ? CPDF_Annot::BoundingRectFromQuadPoints(pAnnotDict) + : pAnnotDict->GetRectFor(pdfium::annotation::kRect); + pStreamDict->SetRectFor("BBox", rect); + pStreamDict->SetFor("Resources", pResourceDict); +} + +bool GenerateCircleAP(CPDF_Document* pDoc, CPDF_Dictionary* pAnnotDict) { + fxcrt::ostringstream sAppStream; + ByteString sExtGSDictName = "GS"; + sAppStream << "/" << sExtGSDictName << " gs "; + + RetainPtr<const CPDF_Array> pInteriorColor = pAnnotDict->GetArrayFor("IC"); + sAppStream << GetColorStringWithDefault( + pInteriorColor.Get(), CFX_Color(CFX_Color::Type::kTransparent), + PaintOperation::kFill); + + sAppStream << GetColorStringWithDefault( + pAnnotDict->GetArrayFor(pdfium::annotation::kC).Get(), + CFX_Color(CFX_Color::Type::kRGB, 0, 0, 0), PaintOperation::kStroke); + + float fBorderWidth = GetBorderWidth(pAnnotDict); + bool bIsStrokeRect = fBorderWidth > 0; + + if (bIsStrokeRect) { + sAppStream << fBorderWidth << " w "; + sAppStream << GetDashPatternString(pAnnotDict); + } + + CFX_FloatRect rect = pAnnotDict->GetRectFor(pdfium::annotation::kRect); + rect.Normalize(); + + if (bIsStrokeRect) { + // Deflating rect because stroking a path entails painting all points + // whose perpendicular distance from the path in user space is less than + // or equal to half the line width. + rect.Deflate(fBorderWidth / 2, fBorderWidth / 2); + } + + const float fMiddleX = (rect.left + rect.right) / 2; + const float fMiddleY = (rect.top + rect.bottom) / 2; + + // |fL| is precalculated approximate value of 4 * tan((3.14 / 2) / 4) / 3, + // where |fL| * radius is a good approximation of control points for + // arc with 90 degrees. + const float fL = 0.5523f; + const float fDeltaX = fL * rect.Width() / 2.0; + const float fDeltaY = fL * rect.Height() / 2.0; + + // Starting point + sAppStream << fMiddleX << " " << rect.top << " m\n"; + // First Bezier Curve + sAppStream << fMiddleX + fDeltaX << " " << rect.top << " " << rect.right + << " " << fMiddleY + fDeltaY << " " << rect.right << " " + << fMiddleY << " c\n"; + // Second Bezier Curve + sAppStream << rect.right << " " << fMiddleY - fDeltaY << " " + << fMiddleX + fDeltaX << " " << rect.bottom << " " << fMiddleX + << " " << rect.bottom << " c\n"; + // Third Bezier Curve + sAppStream << fMiddleX - fDeltaX << " " << rect.bottom << " " << rect.left + << " " << fMiddleY - fDeltaY << " " << rect.left << " " << fMiddleY + << " c\n"; + // Fourth Bezier Curve + sAppStream << rect.left << " " << fMiddleY + fDeltaY << " " + << fMiddleX - fDeltaX << " " << rect.top << " " << fMiddleX << " " + << rect.top << " c\n"; + + bool bIsFillRect = pInteriorColor && !pInteriorColor->IsEmpty(); + sAppStream << GetPaintOperatorString(bIsStrokeRect, bIsFillRect) << "\n"; + + auto pExtGStateDict = + GenerateExtGStateDict(*pAnnotDict, sExtGSDictName, "Normal"); + auto pResourceDict = + GenerateResourceDict(pDoc, std::move(pExtGStateDict), nullptr); + GenerateAndSetAPDict(pDoc, pAnnotDict, &sAppStream, std::move(pResourceDict), + false /*IsTextMarkupAnnotation*/); + return true; +} + +bool GenerateHighlightAP(CPDF_Document* pDoc, CPDF_Dictionary* pAnnotDict) { + fxcrt::ostringstream sAppStream; + ByteString sExtGSDictName = "GS"; + sAppStream << "/" << sExtGSDictName << " gs "; + + sAppStream << GetColorStringWithDefault( + pAnnotDict->GetArrayFor(pdfium::annotation::kC).Get(), + CFX_Color(CFX_Color::Type::kRGB, 1, 1, 0), PaintOperation::kFill); + + RetainPtr<const CPDF_Array> pArray = pAnnotDict->GetArrayFor("QuadPoints"); + if (pArray) { + size_t nQuadPointCount = CPDF_Annot::QuadPointCount(pArray.Get()); + for (size_t i = 0; i < nQuadPointCount; ++i) { + CFX_FloatRect rect = CPDF_Annot::RectFromQuadPoints(pAnnotDict, i); + rect.Normalize(); + + sAppStream << rect.left << " " << rect.top << " m " << rect.right << " " + << rect.top << " l " << rect.right << " " << rect.bottom + << " l " << rect.left << " " << rect.bottom << " l h f\n"; + } + } + + auto pExtGStateDict = + GenerateExtGStateDict(*pAnnotDict, sExtGSDictName, "Multiply"); + auto pResourceDict = + GenerateResourceDict(pDoc, std::move(pExtGStateDict), nullptr); + GenerateAndSetAPDict(pDoc, pAnnotDict, &sAppStream, std::move(pResourceDict), + true /*IsTextMarkupAnnotation*/); + + return true; +} + +bool GenerateInkAP(CPDF_Document* pDoc, CPDF_Dictionary* pAnnotDict) { + RetainPtr<const CPDF_Array> pInkList = pAnnotDict->GetArrayFor("InkList"); + if (!pInkList || pInkList->IsEmpty()) + return false; + + float fBorderWidth = GetBorderWidth(pAnnotDict); + const bool bIsStroke = fBorderWidth > 0; + if (!bIsStroke) + return false; + + ByteString sExtGSDictName = "GS"; + fxcrt::ostringstream sAppStream; + sAppStream << "/" << sExtGSDictName << " gs "; + sAppStream << GetColorStringWithDefault( + pAnnotDict->GetArrayFor(pdfium::annotation::kC).Get(), + CFX_Color(CFX_Color::Type::kRGB, 0, 0, 0), PaintOperation::kStroke); + + sAppStream << fBorderWidth << " w "; + sAppStream << GetDashPatternString(pAnnotDict); + + // Set inflated rect as a new rect because paths near the border with large + // width should not be clipped to the original rect. + CFX_FloatRect rect = pAnnotDict->GetRectFor(pdfium::annotation::kRect); + rect.Inflate(fBorderWidth / 2, fBorderWidth / 2); + pAnnotDict->SetRectFor(pdfium::annotation::kRect, rect); + + for (size_t i = 0; i < pInkList->size(); i++) { + RetainPtr<const CPDF_Array> pInkCoordList = pInkList->GetArrayAt(i); + if (!pInkCoordList || pInkCoordList->size() < 2) + continue; + + sAppStream << pInkCoordList->GetFloatAt(0) << " " + << pInkCoordList->GetFloatAt(1) << " m "; + + for (size_t j = 0; j < pInkCoordList->size() - 1; j += 2) { + sAppStream << pInkCoordList->GetFloatAt(j) << " " + << pInkCoordList->GetFloatAt(j + 1) << " l "; + } + + sAppStream << "S\n"; + } + + auto pExtGStateDict = + GenerateExtGStateDict(*pAnnotDict, sExtGSDictName, "Normal"); + auto pResourceDict = + GenerateResourceDict(pDoc, std::move(pExtGStateDict), nullptr); + GenerateAndSetAPDict(pDoc, pAnnotDict, &sAppStream, std::move(pResourceDict), + false /*IsTextMarkupAnnotation*/); + return true; +} + +bool GenerateTextAP(CPDF_Document* pDoc, CPDF_Dictionary* pAnnotDict) { + fxcrt::ostringstream sAppStream; + ByteString sExtGSDictName = "GS"; + sAppStream << "/" << sExtGSDictName << " gs "; + + CFX_FloatRect rect = pAnnotDict->GetRectFor(pdfium::annotation::kRect); + const float fNoteLength = 20; + CFX_FloatRect noteRect(rect.left, rect.bottom, rect.left + fNoteLength, + rect.bottom + fNoteLength); + pAnnotDict->SetRectFor(pdfium::annotation::kRect, noteRect); + + sAppStream << GenerateTextSymbolAP(noteRect); + + auto pExtGStateDict = + GenerateExtGStateDict(*pAnnotDict, sExtGSDictName, "Normal"); + auto pResourceDict = + GenerateResourceDict(pDoc, std::move(pExtGStateDict), nullptr); + GenerateAndSetAPDict(pDoc, pAnnotDict, &sAppStream, std::move(pResourceDict), + false /*IsTextMarkupAnnotation*/); + return true; +} + +bool GenerateUnderlineAP(CPDF_Document* pDoc, CPDF_Dictionary* pAnnotDict) { + fxcrt::ostringstream sAppStream; + ByteString sExtGSDictName = "GS"; + sAppStream << "/" << sExtGSDictName << " gs "; + + sAppStream << GetColorStringWithDefault( + pAnnotDict->GetArrayFor(pdfium::annotation::kC).Get(), + CFX_Color(CFX_Color::Type::kRGB, 0, 0, 0), PaintOperation::kStroke); + + RetainPtr<const CPDF_Array> pArray = pAnnotDict->GetArrayFor("QuadPoints"); + if (pArray) { + static constexpr float kLineWidth = 1.0f; + sAppStream << kLineWidth << " w "; + size_t nQuadPointCount = CPDF_Annot::QuadPointCount(pArray.Get()); + for (size_t i = 0; i < nQuadPointCount; ++i) { + CFX_FloatRect rect = CPDF_Annot::RectFromQuadPoints(pAnnotDict, i); + rect.Normalize(); + sAppStream << rect.left << " " << rect.bottom + kLineWidth << " m " + << rect.right << " " << rect.bottom + kLineWidth << " l S\n"; + } + } + + auto pExtGStateDict = + GenerateExtGStateDict(*pAnnotDict, sExtGSDictName, "Normal"); + auto pResourceDict = + GenerateResourceDict(pDoc, std::move(pExtGStateDict), nullptr); + GenerateAndSetAPDict(pDoc, pAnnotDict, &sAppStream, std::move(pResourceDict), + true /*IsTextMarkupAnnotation*/); + return true; +} + +bool GeneratePopupAP(CPDF_Document* pDoc, CPDF_Dictionary* pAnnotDict) { + fxcrt::ostringstream sAppStream; + ByteString sExtGSDictName = "GS"; + sAppStream << "/" << sExtGSDictName << " gs\n"; + + sAppStream << GenerateColorAP(CFX_Color(CFX_Color::Type::kRGB, 1, 1, 0), + PaintOperation::kFill); + sAppStream << GenerateColorAP(CFX_Color(CFX_Color::Type::kRGB, 0, 0, 0), + PaintOperation::kStroke); + + const float fBorderWidth = 1; + sAppStream << fBorderWidth << " w\n"; + + CFX_FloatRect rect = pAnnotDict->GetRectFor(pdfium::annotation::kRect); + rect.Normalize(); + rect.Deflate(fBorderWidth / 2, fBorderWidth / 2); + + sAppStream << rect.left << " " << rect.bottom << " " << rect.Width() << " " + << rect.Height() << " re b\n"; + + ByteString sFontName = "FONT"; + RetainPtr<CPDF_Dictionary> pResourceFontDict = + GenerateResourceFontDict(pDoc, sFontName); + + auto* pData = CPDF_DocPageData::FromDocument(pDoc); + RetainPtr<CPDF_Font> pDefFont = pData->GetFont(pResourceFontDict); + if (!pDefFont) + return false; + + RetainPtr<CPDF_Dictionary> pExtGStateDict = + GenerateExtGStateDict(*pAnnotDict, sExtGSDictName, "Normal"); + RetainPtr<CPDF_Dictionary> pResourceDict = GenerateResourceDict( + pDoc, std::move(pExtGStateDict), std::move(pResourceFontDict)); + + sAppStream << GetPopupContentsString(pDoc, *pAnnotDict, std::move(pDefFont), + sFontName); + GenerateAndSetAPDict(pDoc, pAnnotDict, &sAppStream, std::move(pResourceDict), + false /*IsTextMarkupAnnotation*/); + return true; +} + +bool GenerateSquareAP(CPDF_Document* pDoc, CPDF_Dictionary* pAnnotDict) { + const ByteString sExtGSDictName = "GS"; + fxcrt::ostringstream sAppStream; + sAppStream << "/" << sExtGSDictName << " gs "; + + RetainPtr<const CPDF_Array> pInteriorColor = pAnnotDict->GetArrayFor("IC"); + sAppStream << GetColorStringWithDefault( + pInteriorColor.Get(), CFX_Color(CFX_Color::Type::kTransparent), + PaintOperation::kFill); + + sAppStream << GetColorStringWithDefault( + pAnnotDict->GetArrayFor(pdfium::annotation::kC).Get(), + CFX_Color(CFX_Color::Type::kRGB, 0, 0, 0), PaintOperation::kStroke); + + float fBorderWidth = GetBorderWidth(pAnnotDict); + const bool bIsStrokeRect = fBorderWidth > 0; + if (bIsStrokeRect) { + sAppStream << fBorderWidth << " w "; + sAppStream << GetDashPatternString(pAnnotDict); + } + + CFX_FloatRect rect = pAnnotDict->GetRectFor(pdfium::annotation::kRect); + rect.Normalize(); + + if (bIsStrokeRect) { + // Deflating rect because stroking a path entails painting all points + // whose perpendicular distance from the path in user space is less than + // or equal to half the line width. + rect.Deflate(fBorderWidth / 2, fBorderWidth / 2); + } + + const bool bIsFillRect = pInteriorColor && (pInteriorColor->size() > 0); + sAppStream << rect.left << " " << rect.bottom << " " << rect.Width() << " " + << rect.Height() << " re " + << GetPaintOperatorString(bIsStrokeRect, bIsFillRect) << "\n"; + + auto pExtGStateDict = + GenerateExtGStateDict(*pAnnotDict, sExtGSDictName, "Normal"); + auto pResourceDict = + GenerateResourceDict(pDoc, std::move(pExtGStateDict), nullptr); + GenerateAndSetAPDict(pDoc, pAnnotDict, &sAppStream, std::move(pResourceDict), + false /*IsTextMarkupAnnotation*/); + return true; +} + +bool GenerateSquigglyAP(CPDF_Document* pDoc, CPDF_Dictionary* pAnnotDict) { + fxcrt::ostringstream sAppStream; + ByteString sExtGSDictName = "GS"; + sAppStream << "/" << sExtGSDictName << " gs "; + + sAppStream << GetColorStringWithDefault( + pAnnotDict->GetArrayFor(pdfium::annotation::kC).Get(), + CFX_Color(CFX_Color::Type::kRGB, 0, 0, 0), PaintOperation::kStroke); + + RetainPtr<const CPDF_Array> pArray = pAnnotDict->GetArrayFor("QuadPoints"); + if (pArray) { + static constexpr float kLineWidth = 1.0f; + static constexpr float kDelta = 2.0f; + sAppStream << kLineWidth << " w "; + size_t nQuadPointCount = CPDF_Annot::QuadPointCount(pArray.Get()); + for (size_t i = 0; i < nQuadPointCount; ++i) { + CFX_FloatRect rect = CPDF_Annot::RectFromQuadPoints(pAnnotDict, i); + rect.Normalize(); + + const float fTop = rect.bottom + kDelta; + const float fBottom = rect.bottom; + sAppStream << rect.left << " " << fTop << " m "; + + float fX = rect.left + kDelta; + bool isUpwards = false; + while (fX < rect.right) { + sAppStream << fX << " " << (isUpwards ? fTop : fBottom) << " l "; + fX += kDelta; + isUpwards = !isUpwards; + } + + float fRemainder = rect.right - (fX - kDelta); + if (isUpwards) + sAppStream << rect.right << " " << fBottom + fRemainder << " l "; + else + sAppStream << rect.right << " " << fTop - fRemainder << " l "; + + sAppStream << "S\n"; + } + } + + auto pExtGStateDict = + GenerateExtGStateDict(*pAnnotDict, sExtGSDictName, "Normal"); + auto pResourceDict = + GenerateResourceDict(pDoc, std::move(pExtGStateDict), nullptr); + GenerateAndSetAPDict(pDoc, pAnnotDict, &sAppStream, std::move(pResourceDict), + true /*IsTextMarkupAnnotation*/); + return true; +} + +bool GenerateStrikeOutAP(CPDF_Document* pDoc, CPDF_Dictionary* pAnnotDict) { + fxcrt::ostringstream sAppStream; + ByteString sExtGSDictName = "GS"; + sAppStream << "/" << sExtGSDictName << " gs "; + + sAppStream << GetColorStringWithDefault( + pAnnotDict->GetArrayFor(pdfium::annotation::kC).Get(), + CFX_Color(CFX_Color::Type::kRGB, 0, 0, 0), PaintOperation::kStroke); + + RetainPtr<const CPDF_Array> pArray = pAnnotDict->GetArrayFor("QuadPoints"); + if (pArray) { + static constexpr float kLineWidth = 1.0f; + size_t nQuadPointCount = CPDF_Annot::QuadPointCount(pArray.Get()); + for (size_t i = 0; i < nQuadPointCount; ++i) { + CFX_FloatRect rect = CPDF_Annot::RectFromQuadPoints(pAnnotDict, i); + rect.Normalize(); + + float fY = (rect.top + rect.bottom) / 2; + sAppStream << kLineWidth << " w " << rect.left << " " << fY << " m " + << rect.right << " " << fY << " l S\n"; + } + } + + auto pExtGStateDict = + GenerateExtGStateDict(*pAnnotDict, sExtGSDictName, "Normal"); + auto pResourceDict = + GenerateResourceDict(pDoc, std::move(pExtGStateDict), nullptr); + GenerateAndSetAPDict(pDoc, pAnnotDict, &sAppStream, std::move(pResourceDict), + true /*IsTextMarkupAnnotation*/); + return true; +} + +} // namespace + +// static +void CPDF_GenerateAP::GenerateFormAP(CPDF_Document* pDoc, + CPDF_Dictionary* pAnnotDict, + FormType type) { + RetainPtr<CPDF_Dictionary> pRootDict = pDoc->GetMutableRoot(); + if (!pRootDict) + return; + + RetainPtr<CPDF_Dictionary> pFormDict = + pRootDict->GetMutableDictFor("AcroForm"); + if (!pFormDict) + return; + + ByteString DA; + RetainPtr<const CPDF_Object> pDAObj = + CPDF_FormField::GetFieldAttrForDict(pAnnotDict, "DA"); + if (pDAObj) + DA = pDAObj->GetString(); + if (DA.IsEmpty()) + DA = pFormDict->GetByteStringFor("DA"); + if (DA.IsEmpty()) + return; + + CPDF_DefaultAppearance appearance(DA); + + float fFontSize = 0; + absl::optional<ByteString> font = appearance.GetFont(&fFontSize); + if (!font.has_value()) + return; + + ByteString font_name = font.value(); + + CFX_Color crText = fpdfdoc::CFXColorFromString(DA); + RetainPtr<CPDF_Dictionary> pDRDict = pFormDict->GetMutableDictFor("DR"); + if (!pDRDict) + return; + + RetainPtr<CPDF_Dictionary> pDRFontDict = pDRDict->GetMutableDictFor("Font"); + if (!ValidateFontResourceDict(pDRFontDict.Get())) + return; + + RetainPtr<CPDF_Dictionary> pFontDict = + pDRFontDict->GetMutableDictFor(font_name); + if (!pFontDict) { + pFontDict = pDoc->NewIndirect<CPDF_Dictionary>(); + pFontDict->SetNewFor<CPDF_Name>("Type", "Font"); + pFontDict->SetNewFor<CPDF_Name>("Subtype", "Type1"); + pFontDict->SetNewFor<CPDF_Name>("BaseFont", CFX_Font::kDefaultAnsiFontName); + pFontDict->SetNewFor<CPDF_Name>("Encoding", + pdfium::font_encodings::kWinAnsiEncoding); + pDRFontDict->SetNewFor<CPDF_Reference>(font_name, pDoc, + pFontDict->GetObjNum()); + } + auto* pData = CPDF_DocPageData::FromDocument(pDoc); + RetainPtr<CPDF_Font> pDefFont = pData->GetFont(pFontDict); + if (!pDefFont) + return; + + CFX_FloatRect rcAnnot = pAnnotDict->GetRectFor(pdfium::annotation::kRect); + RetainPtr<const CPDF_Dictionary> pMKDict = pAnnotDict->GetDictFor("MK"); + int32_t nRotate = + pMKDict ? pMKDict->GetIntegerFor(pdfium::appearance::kR) : 0; + + CFX_FloatRect rcBBox; + CFX_Matrix matrix; + switch (nRotate % 360) { + case 0: + rcBBox = CFX_FloatRect(0, 0, rcAnnot.right - rcAnnot.left, + rcAnnot.top - rcAnnot.bottom); + break; + case 90: + matrix = CFX_Matrix(0, 1, -1, 0, rcAnnot.right - rcAnnot.left, 0); + rcBBox = CFX_FloatRect(0, 0, rcAnnot.top - rcAnnot.bottom, + rcAnnot.right - rcAnnot.left); + break; + case 180: + matrix = CFX_Matrix(-1, 0, 0, -1, rcAnnot.right - rcAnnot.left, + rcAnnot.top - rcAnnot.bottom); + rcBBox = CFX_FloatRect(0, 0, rcAnnot.right - rcAnnot.left, + rcAnnot.top - rcAnnot.bottom); + break; + case 270: + matrix = CFX_Matrix(0, -1, 1, 0, 0, rcAnnot.top - rcAnnot.bottom); + rcBBox = CFX_FloatRect(0, 0, rcAnnot.top - rcAnnot.bottom, + rcAnnot.right - rcAnnot.left); + break; + } + + BorderStyle nBorderStyle = BorderStyle::kSolid; + float fBorderWidth = 1; + CPVT_Dash dsBorder(3, 0, 0); + CFX_Color crLeftTop; + CFX_Color crRightBottom; + if (RetainPtr<const CPDF_Dictionary> pBSDict = pAnnotDict->GetDictFor("BS")) { + if (pBSDict->KeyExist("W")) + fBorderWidth = pBSDict->GetFloatFor("W"); + + if (RetainPtr<const CPDF_Array> pArray = pBSDict->GetArrayFor("D")) { + dsBorder = CPVT_Dash(pArray->GetIntegerAt(0), pArray->GetIntegerAt(1), + pArray->GetIntegerAt(2)); + } + if (pBSDict->GetByteStringFor("S").GetLength()) { + switch (pBSDict->GetByteStringFor("S")[0]) { + case 'S': + nBorderStyle = BorderStyle::kSolid; + break; + case 'D': + nBorderStyle = BorderStyle::kDash; + break; + case 'B': + nBorderStyle = BorderStyle::kBeveled; + fBorderWidth *= 2; + crLeftTop = CFX_Color(CFX_Color::Type::kGray, 1); + crRightBottom = CFX_Color(CFX_Color::Type::kGray, 0.5); + break; + case 'I': + nBorderStyle = BorderStyle::kInset; + fBorderWidth *= 2; + crLeftTop = CFX_Color(CFX_Color::Type::kGray, 0.5); + crRightBottom = CFX_Color(CFX_Color::Type::kGray, 0.75); + break; + case 'U': + nBorderStyle = BorderStyle::kUnderline; + break; + } + } + } + CFX_Color crBorder; + CFX_Color crBG; + if (pMKDict) { + RetainPtr<const CPDF_Array> pArray = + pMKDict->GetArrayFor(pdfium::appearance::kBC); + if (pArray) + crBorder = fpdfdoc::CFXColorFromArray(*pArray); + pArray = pMKDict->GetArrayFor(pdfium::appearance::kBG); + if (pArray) + crBG = fpdfdoc::CFXColorFromArray(*pArray); + } + fxcrt::ostringstream sAppStream; + ByteString sBG = GenerateColorAP(crBG, PaintOperation::kFill); + if (sBG.GetLength() > 0) { + sAppStream << "q\n" + << sBG << rcBBox.left << " " << rcBBox.bottom << " " + << rcBBox.Width() << " " << rcBBox.Height() << " re f\n" + << "Q\n"; + } + ByteString sBorderStream = + GenerateBorderAP(rcBBox, fBorderWidth, crBorder, crLeftTop, crRightBottom, + nBorderStyle, dsBorder); + if (sBorderStream.GetLength() > 0) + sAppStream << "q\n" << sBorderStream << "Q\n"; + + CFX_FloatRect rcBody = + CFX_FloatRect(rcBBox.left + fBorderWidth, rcBBox.bottom + fBorderWidth, + rcBBox.right - fBorderWidth, rcBBox.top - fBorderWidth); + rcBody.Normalize(); + + RetainPtr<CPDF_Dictionary> pAPDict = + pAnnotDict->GetOrCreateDictFor(pdfium::annotation::kAP); + RetainPtr<CPDF_Stream> pNormalStream = pAPDict->GetMutableStreamFor("N"); + if (!pNormalStream) { + pNormalStream = pDoc->NewIndirect<CPDF_Stream>(); + pAPDict->SetNewFor<CPDF_Reference>("N", pDoc, pNormalStream->GetObjNum()); + } + RetainPtr<CPDF_Dictionary> pStreamDict = pNormalStream->GetMutableDict(); + if (pStreamDict) { + RetainPtr<CPDF_Dictionary> pStreamResList = + pStreamDict->GetMutableDictFor("Resources"); + if (pStreamResList) { + RetainPtr<CPDF_Dictionary> pStreamResFontList = + pStreamResList->GetMutableDictFor("Font"); + if (pStreamResFontList) { + if (!ValidateFontResourceDict(pStreamResFontList.Get())) + return; + } else { + pStreamResFontList = pStreamResList->SetNewFor<CPDF_Dictionary>("Font"); + } + if (!pStreamResFontList->KeyExist(font_name)) { + pStreamResFontList->SetNewFor<CPDF_Reference>(font_name, pDoc, + pFontDict->GetObjNum()); + } + } else { + pStreamDict->SetFor("Resources", pFormDict->GetDictFor("DR")->Clone()); + } + pStreamDict->SetMatrixFor("Matrix", matrix); + pStreamDict->SetRectFor("BBox", rcBBox); + } + CPVT_FontMap map( + pDoc, pStreamDict ? pStreamDict->GetMutableDictFor("Resources") : nullptr, + std::move(pDefFont), font_name); + CPVT_VariableText::Provider prd(&map); + + switch (type) { + case CPDF_GenerateAP::kTextField: { + RetainPtr<const CPDF_Object> pV = CPDF_FormField::GetFieldAttrForDict( + pAnnotDict, pdfium::form_fields::kV); + WideString swValue = pV ? pV->GetUnicodeText() : WideString(); + RetainPtr<const CPDF_Object> pQ = + CPDF_FormField::GetFieldAttrForDict(pAnnotDict, "Q"); + int32_t nAlign = pQ ? pQ->GetInteger() : 0; + RetainPtr<const CPDF_Object> pFf = CPDF_FormField::GetFieldAttrForDict( + pAnnotDict, pdfium::form_fields::kFf); + uint32_t dwFlags = pFf ? pFf->GetInteger() : 0; + RetainPtr<const CPDF_Object> pMaxLen = + CPDF_FormField::GetFieldAttrForDict(pAnnotDict, "MaxLen"); + uint32_t dwMaxLen = pMaxLen ? pMaxLen->GetInteger() : 0; + CPVT_VariableText vt(&prd); + vt.SetPlateRect(rcBody); + vt.SetAlignment(nAlign); + if (FXSYS_IsFloatZero(fFontSize)) + vt.SetAutoFontSize(true); + else + vt.SetFontSize(fFontSize); + + bool bMultiLine = (dwFlags >> 12) & 1; + if (bMultiLine) { + vt.SetMultiLine(true); + vt.SetAutoReturn(true); + } + uint16_t subWord = 0; + if ((dwFlags >> 13) & 1) { + subWord = '*'; + vt.SetPasswordChar(subWord); + } + bool bCharArray = (dwFlags >> 24) & 1; + if (bCharArray) + vt.SetCharArray(dwMaxLen); + else + vt.SetLimitChar(dwMaxLen); + + vt.Initialize(); + vt.SetText(swValue); + vt.RearrangeAll(); + CFX_FloatRect rcContent = vt.GetContentRect(); + CFX_PointF ptOffset; + if (!bMultiLine) { + ptOffset = + CFX_PointF(0.0f, (rcContent.Height() - rcBody.Height()) / 2.0f); + } + ByteString sBody = GenerateEditAP(&map, vt.GetIterator(), ptOffset, + !bCharArray, subWord); + if (sBody.GetLength() > 0) { + sAppStream << "/Tx BMC\n" + << "q\n"; + if (rcContent.Width() > rcBody.Width() || + rcContent.Height() > rcBody.Height()) { + sAppStream << rcBody.left << " " << rcBody.bottom << " " + << rcBody.Width() << " " << rcBody.Height() + << " re\nW\nn\n"; + } + sAppStream << "BT\n" + << GenerateColorAP(crText, PaintOperation::kFill) << sBody + << "ET\n" + << "Q\nEMC\n"; + } + break; + } + case CPDF_GenerateAP::kComboBox: { + RetainPtr<const CPDF_Object> pV = CPDF_FormField::GetFieldAttrForDict( + pAnnotDict, pdfium::form_fields::kV); + WideString swValue = pV ? pV->GetUnicodeText() : WideString(); + CPVT_VariableText vt(&prd); + CFX_FloatRect rcButton = rcBody; + rcButton.left = rcButton.right - 13; + rcButton.Normalize(); + CFX_FloatRect rcEdit = rcBody; + rcEdit.right = rcButton.left; + rcEdit.Normalize(); + vt.SetPlateRect(rcEdit); + if (FXSYS_IsFloatZero(fFontSize)) + vt.SetAutoFontSize(true); + else + vt.SetFontSize(fFontSize); + + vt.Initialize(); + vt.SetText(swValue); + vt.RearrangeAll(); + CFX_FloatRect rcContent = vt.GetContentRect(); + CFX_PointF ptOffset = + CFX_PointF(0.0f, (rcContent.Height() - rcEdit.Height()) / 2.0f); + ByteString sEdit = + GenerateEditAP(&map, vt.GetIterator(), ptOffset, true, 0); + if (sEdit.GetLength() > 0) { + sAppStream << "/Tx BMC\n" + << "q\n"; + sAppStream << rcEdit.left << " " << rcEdit.bottom << " " + << rcEdit.Width() << " " << rcEdit.Height() << " re\nW\nn\n"; + sAppStream << "BT\n" + << GenerateColorAP(crText, PaintOperation::kFill) << sEdit + << "ET\n" + << "Q\nEMC\n"; + } + ByteString sButton = + GenerateColorAP(CFX_Color(CFX_Color::Type::kRGB, 220.0f / 255.0f, + 220.0f / 255.0f, 220.0f / 255.0f), + PaintOperation::kFill); + if (sButton.GetLength() > 0 && !rcButton.IsEmpty()) { + sAppStream << "q\n" << sButton; + sAppStream << rcButton.left << " " << rcButton.bottom << " " + << rcButton.Width() << " " << rcButton.Height() << " re f\n"; + sAppStream << "Q\n"; + ByteString sButtonBorder = + GenerateBorderAP(rcButton, 2, CFX_Color(CFX_Color::Type::kGray, 0), + CFX_Color(CFX_Color::Type::kGray, 1), + CFX_Color(CFX_Color::Type::kGray, 0.5), + BorderStyle::kBeveled, CPVT_Dash(3, 0, 0)); + if (sButtonBorder.GetLength() > 0) + sAppStream << "q\n" << sButtonBorder << "Q\n"; + + CFX_PointF ptCenter = CFX_PointF((rcButton.left + rcButton.right) / 2, + (rcButton.top + rcButton.bottom) / 2); + if (FXSYS_IsFloatBigger(rcButton.Width(), 6) && + FXSYS_IsFloatBigger(rcButton.Height(), 6)) { + sAppStream << "q\n" + << " 0 g\n"; + sAppStream << ptCenter.x - 3 << " " << ptCenter.y + 1.5f << " m\n"; + sAppStream << ptCenter.x + 3 << " " << ptCenter.y + 1.5f << " l\n"; + sAppStream << ptCenter.x << " " << ptCenter.y - 1.5f << " l\n"; + sAppStream << ptCenter.x - 3 << " " << ptCenter.y + 1.5f << " l f\n"; + sAppStream << sButton << "Q\n"; + } + } + break; + } + case CPDF_GenerateAP::kListBox: { + RetainPtr<const CPDF_Array> pOpts = + ToArray(CPDF_FormField::GetFieldAttrForDict(pAnnotDict, "Opt")); + RetainPtr<const CPDF_Array> pSels = + ToArray(CPDF_FormField::GetFieldAttrForDict(pAnnotDict, "I")); + RetainPtr<const CPDF_Object> pTi = + CPDF_FormField::GetFieldAttrForDict(pAnnotDict, "TI"); + int32_t nTop = pTi ? pTi->GetInteger() : 0; + fxcrt::ostringstream sBody; + if (pOpts) { + float fy = rcBody.top; + for (size_t i = nTop, sz = pOpts->size(); i < sz; i++) { + if (FXSYS_IsFloatSmaller(fy, rcBody.bottom)) + break; + + if (RetainPtr<const CPDF_Object> pOpt = pOpts->GetDirectObjectAt(i)) { + WideString swItem; + if (pOpt->IsString()) { + swItem = pOpt->GetUnicodeText(); + } else if (const CPDF_Array* pArray = pOpt->AsArray()) { + RetainPtr<const CPDF_Object> pDirectObj = + pArray->GetDirectObjectAt(1); + if (pDirectObj) + swItem = pDirectObj->GetUnicodeText(); + } + bool bSelected = false; + if (pSels) { + for (size_t s = 0, ssz = pSels->size(); s < ssz; s++) { + int value = pSels->GetIntegerAt(s); + if (value >= 0 && i == static_cast<size_t>(value)) { + bSelected = true; + break; + } + } + } + CPVT_VariableText vt(&prd); + vt.SetPlateRect( + CFX_FloatRect(rcBody.left, 0.0f, rcBody.right, 0.0f)); + vt.SetFontSize(FXSYS_IsFloatZero(fFontSize) ? 12.0f : fFontSize); + vt.Initialize(); + vt.SetText(swItem); + vt.RearrangeAll(); + + float fItemHeight = vt.GetContentRect().Height(); + if (bSelected) { + CFX_FloatRect rcItem = CFX_FloatRect( + rcBody.left, fy - fItemHeight, rcBody.right, fy); + sBody << "q\n" + << GenerateColorAP( + CFX_Color(CFX_Color::Type::kRGB, 0, 51.0f / 255.0f, + 113.0f / 255.0f), + PaintOperation::kFill) + << rcItem.left << " " << rcItem.bottom << " " + << rcItem.Width() << " " << rcItem.Height() << " re f\n" + << "Q\n"; + sBody << "BT\n" + << GenerateColorAP(CFX_Color(CFX_Color::Type::kGray, 1), + PaintOperation::kFill) + << GenerateEditAP(&map, vt.GetIterator(), + CFX_PointF(0.0f, fy), true, 0) + << "ET\n"; + } else { + sBody << "BT\n" + << GenerateColorAP(crText, PaintOperation::kFill) + << GenerateEditAP(&map, vt.GetIterator(), + CFX_PointF(0.0f, fy), true, 0) + << "ET\n"; + } + fy -= fItemHeight; + } + } + } + if (sBody.tellp() > 0) { + sAppStream << "/Tx BMC\nq\n" + << rcBody.left << " " << rcBody.bottom << " " + << rcBody.Width() << " " << rcBody.Height() << " re\nW\nn\n" + << sBody.str() << "Q\nEMC\n"; + } + break; + } + } + + if (!pNormalStream) + return; + + pNormalStream->SetDataFromStringstreamAndRemoveFilter(&sAppStream); + pStreamDict = pNormalStream->GetMutableDict(); + if (!pStreamDict) + return; + + pStreamDict->SetMatrixFor("Matrix", matrix); + pStreamDict->SetRectFor("BBox", rcBBox); + RetainPtr<CPDF_Dictionary> pStreamResList = + pStreamDict->GetMutableDictFor("Resources"); + if (!pStreamResList) { + pStreamDict->SetFor("Resources", pFormDict->GetDictFor("DR")->Clone()); + return; + } + + RetainPtr<CPDF_Dictionary> pStreamResFontList = + pStreamResList->GetMutableDictFor("Font"); + if (pStreamResFontList) { + if (!ValidateFontResourceDict(pStreamResFontList.Get())) + return; + } else { + pStreamResFontList = pStreamResList->SetNewFor<CPDF_Dictionary>("Font"); + } + + if (!pStreamResFontList->KeyExist(font_name)) { + pStreamResFontList->SetNewFor<CPDF_Reference>(font_name, pDoc, + pFontDict->GetObjNum()); + } +} + +// static +void CPDF_GenerateAP::GenerateEmptyAP(CPDF_Document* pDoc, + CPDF_Dictionary* pAnnotDict) { + auto pExtGStateDict = GenerateExtGStateDict(*pAnnotDict, "GS", "Normal"); + auto pResourceDict = + GenerateResourceDict(pDoc, std::move(pExtGStateDict), nullptr); + + fxcrt::ostringstream sStream; + GenerateAndSetAPDict(pDoc, pAnnotDict, &sStream, std::move(pResourceDict), + false); +} + +// static +bool CPDF_GenerateAP::GenerateAnnotAP(CPDF_Document* pDoc, + CPDF_Dictionary* pAnnotDict, + CPDF_Annot::Subtype subtype) { + switch (subtype) { + case CPDF_Annot::Subtype::CIRCLE: + return GenerateCircleAP(pDoc, pAnnotDict); + case CPDF_Annot::Subtype::HIGHLIGHT: + return GenerateHighlightAP(pDoc, pAnnotDict); + case CPDF_Annot::Subtype::INK: + return GenerateInkAP(pDoc, pAnnotDict); + case CPDF_Annot::Subtype::POPUP: + return GeneratePopupAP(pDoc, pAnnotDict); + case CPDF_Annot::Subtype::SQUARE: + return GenerateSquareAP(pDoc, pAnnotDict); + case CPDF_Annot::Subtype::SQUIGGLY: + return GenerateSquigglyAP(pDoc, pAnnotDict); + case CPDF_Annot::Subtype::STRIKEOUT: + return GenerateStrikeOutAP(pDoc, pAnnotDict); + case CPDF_Annot::Subtype::TEXT: + return GenerateTextAP(pDoc, pAnnotDict); + case CPDF_Annot::Subtype::UNDERLINE: + return GenerateUnderlineAP(pDoc, pAnnotDict); + default: + return false; + } +}
diff --git a/core/fpdfdoc/cpdf_generateap.h b/core/fpdfdoc/cpdf_generateap.h new file mode 100644 index 0000000..520ce4f --- /dev/null +++ b/core/fpdfdoc/cpdf_generateap.h
@@ -0,0 +1,34 @@ +// Copyright 2016 The PDFium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com + +#ifndef CORE_FPDFDOC_CPDF_GENERATEAP_H_ +#define CORE_FPDFDOC_CPDF_GENERATEAP_H_ + +#include "core/fpdfdoc/cpdf_annot.h" + +class CPDF_Dictionary; +class CPDF_Document; + +class CPDF_GenerateAP { + public: + enum FormType { kTextField, kComboBox, kListBox }; + + static void GenerateFormAP(CPDF_Document* pDoc, + CPDF_Dictionary* pAnnotDict, + FormType type); + + static void GenerateEmptyAP(CPDF_Document* pDoc, CPDF_Dictionary* pAnnotDict); + + static bool GenerateAnnotAP(CPDF_Document* pDoc, + CPDF_Dictionary* pAnnotDict, + CPDF_Annot::Subtype subtype); + + CPDF_GenerateAP() = delete; + CPDF_GenerateAP(const CPDF_GenerateAP&) = delete; + CPDF_GenerateAP& operator=(const CPDF_GenerateAP&) = delete; +}; + +#endif // CORE_FPDFDOC_CPDF_GENERATEAP_H_
diff --git a/core/fpdfdoc/cpdf_icon.cpp b/core/fpdfdoc/cpdf_icon.cpp index a450e1e..8c4909a 100644 --- a/core/fpdfdoc/cpdf_icon.cpp +++ b/core/fpdfdoc/cpdf_icon.cpp
@@ -1,4 +1,4 @@ -// Copyright 2019 PDFium Authors. All rights reserved. +// Copyright 2019 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -6,15 +6,18 @@ #include "core/fpdfdoc/cpdf_icon.h" +#include <utility> + #include "core/fpdfapi/parser/cpdf_dictionary.h" #include "core/fpdfapi/parser/cpdf_stream.h" -CPDF_Icon::CPDF_Icon(CPDF_Stream* pStream) : m_pStream(pStream) {} +CPDF_Icon::CPDF_Icon(RetainPtr<const CPDF_Stream> pStream) + : m_pStream(std::move(pStream)) {} CPDF_Icon::~CPDF_Icon() = default; CFX_SizeF CPDF_Icon::GetImageSize() const { - CPDF_Dictionary* pDict = m_pStream->GetDict(); + RetainPtr<const CPDF_Dictionary> pDict = m_pStream->GetDict(); if (!pDict) return CFX_SizeF(); @@ -23,7 +26,7 @@ } CFX_Matrix CPDF_Icon::GetImageMatrix() const { - CPDF_Dictionary* pDict = m_pStream->GetDict(); + RetainPtr<const CPDF_Dictionary> pDict = m_pStream->GetDict(); if (!pDict) return CFX_Matrix(); @@ -31,9 +34,9 @@ } ByteString CPDF_Icon::GetImageAlias() const { - CPDF_Dictionary* pDict = m_pStream->GetDict(); + RetainPtr<const CPDF_Dictionary> pDict = m_pStream->GetDict(); if (!pDict) return ByteString(); - return pDict->GetStringFor("Name"); + return pDict->GetByteStringFor("Name"); }
diff --git a/core/fpdfdoc/cpdf_icon.h b/core/fpdfdoc/cpdf_icon.h index 519fcda..c1d2d27 100644 --- a/core/fpdfdoc/cpdf_icon.h +++ b/core/fpdfdoc/cpdf_icon.h
@@ -1,4 +1,4 @@ -// Copyright 2019 PDFium Authors. All rights reserved. +// Copyright 2019 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -7,15 +7,15 @@ #ifndef CORE_FPDFDOC_CPDF_ICON_H_ #define CORE_FPDFDOC_CPDF_ICON_H_ +#include "core/fxcrt/bytestring.h" #include "core/fxcrt/fx_coordinates.h" -#include "core/fxcrt/fx_string.h" #include "core/fxcrt/retain_ptr.h" class CPDF_Stream; class CPDF_Icon final { public: - CPDF_Icon(CPDF_Stream* pStream); + explicit CPDF_Icon(RetainPtr<const CPDF_Stream> pStream); ~CPDF_Icon(); CFX_SizeF GetImageSize() const; @@ -23,7 +23,7 @@ ByteString GetImageAlias() const; private: - RetainPtr<CPDF_Stream> const m_pStream; + RetainPtr<const CPDF_Stream> const m_pStream; }; #endif // CORE_FPDFDOC_CPDF_ICON_H_
diff --git a/core/fpdfdoc/cpdf_iconfit.cpp b/core/fpdfdoc/cpdf_iconfit.cpp index 55702a3..5eb95e2f 100644 --- a/core/fpdfdoc/cpdf_iconfit.cpp +++ b/core/fpdfdoc/cpdf_iconfit.cpp
@@ -1,4 +1,4 @@ -// Copyright 2016 PDFium Authors. All rights reserved. +// Copyright 2016 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -6,6 +6,9 @@ #include "core/fpdfdoc/cpdf_iconfit.h" +#include <algorithm> +#include <utility> + #include "core/fpdfapi/parser/cpdf_array.h" #include "core/fpdfapi/parser/cpdf_dictionary.h" #include "core/fxcrt/fx_string.h" @@ -16,7 +19,8 @@ } // namespace -CPDF_IconFit::CPDF_IconFit(const CPDF_Dictionary* pDict) : m_pDict(pDict) {} +CPDF_IconFit::CPDF_IconFit(RetainPtr<const CPDF_Dictionary> pDict) + : m_pDict(std::move(pDict)) {} CPDF_IconFit::CPDF_IconFit(const CPDF_IconFit& that) = default; @@ -24,20 +28,20 @@ CPDF_IconFit::ScaleMethod CPDF_IconFit::GetScaleMethod() const { if (!m_pDict) - return Always; + return ScaleMethod::kAlways; - ByteString csSW = m_pDict->GetStringFor("SW", "A"); + ByteString csSW = m_pDict->GetByteStringFor("SW", "A"); if (csSW == "B") - return Bigger; + return ScaleMethod::kBigger; if (csSW == "S") - return Smaller; + return ScaleMethod::kSmaller; if (csSW == "N") - return Never; - return Always; + return ScaleMethod::kNever; + return ScaleMethod::kAlways; } bool CPDF_IconFit::IsProportionalScale() const { - return !m_pDict || m_pDict->GetStringFor("S", "P") != "A"; + return !m_pDict || m_pDict->GetByteStringFor("S", "P") != "A"; } CFX_PointF CPDF_IconFit::GetIconBottomLeftPosition() const { @@ -46,15 +50,15 @@ if (!m_pDict) return {fLeft, fBottom}; - const CPDF_Array* pA = m_pDict->GetArrayFor("A"); + RetainPtr<const CPDF_Array> pA = m_pDict->GetArrayFor("A"); if (!pA) return {fLeft, fBottom}; size_t dwCount = pA->size(); if (dwCount > 0) - fLeft = pA->GetNumberAt(0); + fLeft = pA->GetFloatAt(0); if (dwCount > 1) - fBottom = pA->GetNumberAt(1); + fBottom = pA->GetFloatAt(1); return {fLeft, fBottom}; } @@ -66,11 +70,58 @@ if (!m_pDict) return CFX_PointF(); - const CPDF_Array* pA = m_pDict->GetArrayFor("A"); + RetainPtr<const CPDF_Array> pA = m_pDict->GetArrayFor("A"); if (!pA) return CFX_PointF(); size_t dwCount = pA->size(); - return {dwCount > 0 ? pA->GetNumberAt(0) : 0.0f, - dwCount > 1 ? pA->GetNumberAt(1) : 0.0f}; + return {dwCount > 0 ? pA->GetFloatAt(0) : 0.0f, + dwCount > 1 ? pA->GetFloatAt(1) : 0.0f}; +} + +CFX_VectorF CPDF_IconFit::GetScale(const CFX_SizeF& image_size, + const CFX_FloatRect& rcPlate) const { + float fHScale = 1.0f; + float fVScale = 1.0f; + const float fPlateWidth = rcPlate.Width(); + const float fPlateHeight = rcPlate.Height(); + const float fImageWidth = image_size.width; + const float fImageHeight = image_size.height; + switch (GetScaleMethod()) { + case CPDF_IconFit::ScaleMethod::kAlways: + fHScale = fPlateWidth / std::max(fImageWidth, 1.0f); + fVScale = fPlateHeight / std::max(fImageHeight, 1.0f); + break; + case CPDF_IconFit::ScaleMethod::kBigger: + if (fPlateWidth < fImageWidth) + fHScale = fPlateWidth / std::max(fImageWidth, 1.0f); + if (fPlateHeight < fImageHeight) + fVScale = fPlateHeight / std::max(fImageHeight, 1.0f); + break; + case CPDF_IconFit::ScaleMethod::kSmaller: + if (fPlateWidth > fImageWidth) + fHScale = fPlateWidth / std::max(fImageWidth, 1.0f); + if (fPlateHeight > fImageHeight) + fVScale = fPlateHeight / std::max(fImageHeight, 1.0f); + break; + case CPDF_IconFit::ScaleMethod::kNever: + break; + } + + if (IsProportionalScale()) { + float min_scale = std::min(fHScale, fVScale); + fHScale = min_scale; + fVScale = min_scale; + } + return {fHScale, fVScale}; +} + +CFX_VectorF CPDF_IconFit::GetImageOffset(const CFX_SizeF& image_size, + const CFX_VectorF& scale, + const CFX_FloatRect& rcPlate) const { + const CFX_PointF icon_position = GetIconPosition(); + const float fImageFactWidth = image_size.width * scale.x; + const float fImageFactHeight = image_size.height * scale.y; + return {(rcPlate.Width() - fImageFactWidth) * icon_position.x, + (rcPlate.Height() - fImageFactHeight) * icon_position.y}; }
diff --git a/core/fpdfdoc/cpdf_iconfit.h b/core/fpdfdoc/cpdf_iconfit.h index 86a4918..3e55e1e 100644 --- a/core/fpdfdoc/cpdf_iconfit.h +++ b/core/fpdfdoc/cpdf_iconfit.h
@@ -1,4 +1,4 @@ -// Copyright 2016 PDFium Authors. All rights reserved. +// Copyright 2016 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -8,16 +8,15 @@ #define CORE_FPDFDOC_CPDF_ICONFIT_H_ #include "core/fxcrt/fx_coordinates.h" -#include "core/fxcrt/fx_system.h" #include "core/fxcrt/retain_ptr.h" class CPDF_Dictionary; class CPDF_IconFit { public: - enum ScaleMethod { Always = 0, Bigger, Smaller, Never }; + enum class ScaleMethod { kAlways = 0, kBigger, kSmaller, kNever }; - explicit CPDF_IconFit(const CPDF_Dictionary* pDict); + explicit CPDF_IconFit(RetainPtr<const CPDF_Dictionary> pDict); CPDF_IconFit(const CPDF_IconFit& that); ~CPDF_IconFit(); @@ -25,9 +24,15 @@ bool IsProportionalScale() const; bool GetFittingBounds() const; CFX_PointF GetIconBottomLeftPosition() const; - CFX_PointF GetIconPosition() const; + CFX_VectorF GetScale(const CFX_SizeF& image_size, + const CFX_FloatRect& rcPlate) const; + CFX_VectorF GetImageOffset(const CFX_SizeF& image_size, + const CFX_VectorF& scale, + const CFX_FloatRect& rcPlate) const; private: + CFX_PointF GetIconPosition() const; + RetainPtr<const CPDF_Dictionary> const m_pDict; };
diff --git a/core/fpdfdoc/cpdf_interactiveform.cpp b/core/fpdfdoc/cpdf_interactiveform.cpp index a4a1025..de7fd71 100644 --- a/core/fpdfdoc/cpdf_interactiveform.cpp +++ b/core/fpdfdoc/cpdf_interactiveform.cpp
@@ -1,4 +1,4 @@ -// Copyright 2016 PDFium Authors. All rights reserved. +// Copyright 2016 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -11,6 +11,7 @@ #include "build/build_config.h" #include "constants/form_fields.h" +#include "constants/form_flags.h" #include "constants/stream_dict_common.h" #include "core/fpdfapi/font/cpdf_font.h" #include "core/fpdfapi/font/cpdf_fontencoding.h" @@ -22,24 +23,96 @@ #include "core/fpdfapi/parser/cpdf_document.h" #include "core/fpdfapi/parser/cpdf_name.h" #include "core/fpdfapi/parser/cpdf_reference.h" +#include "core/fpdfapi/parser/cpdf_stream.h" #include "core/fpdfapi/parser/cpdf_string.h" #include "core/fpdfapi/parser/fpdf_parser_utility.h" #include "core/fpdfdoc/cpdf_filespec.h" #include "core/fpdfdoc/cpdf_formcontrol.h" #include "core/fxcrt/fx_codepage.h" -#include "core/fxge/cfx_substfont.h" +#include "core/fxcrt/stl_util.h" #include "core/fxge/fx_font.h" -#include "third_party/base/ptr_util.h" -#include "third_party/base/stl_util.h" +#include "third_party/abseil-cpp/absl/types/optional.h" +#include "third_party/base/check.h" +#include "third_party/base/containers/contains.h" +#include "third_party/base/numerics/safe_conversions.h" namespace { const int nMaxRecursion = 32; -void AddFont(CPDF_Dictionary*& pFormDict, - CPDF_Document* pDocument, - const RetainPtr<CPDF_Font>& pFont, - ByteString* csNameTag); +#if BUILDFLAG(IS_WIN) +struct PDF_FONTDATA { + bool bFind; + LOGFONTA lf; +}; + +int CALLBACK EnumFontFamExProc(ENUMLOGFONTEXA* lpelfe, + NEWTEXTMETRICEX* lpntme, + DWORD FontType, + LPARAM lParam) { + if (FontType != 0x004 || strchr(lpelfe->elfLogFont.lfFaceName, '@')) + return 1; + + PDF_FONTDATA* pData = (PDF_FONTDATA*)lParam; + memcpy(&pData->lf, &lpelfe->elfLogFont, sizeof(LOGFONTA)); + pData->bFind = true; + return 0; +} + +bool RetrieveSpecificFont(FX_Charset charSet, + LPCSTR pcsFontName, + LOGFONTA& lf) { + memset(&lf, 0, sizeof(LOGFONTA)); + lf.lfCharSet = static_cast<int>(charSet); + lf.lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE; + if (pcsFontName) { + // TODO(dsinclair): Should this be strncpy? + // NOLINTNEXTLINE(runtime/printf) + strcpy(lf.lfFaceName, pcsFontName); + } + + PDF_FONTDATA fd; + memset(&fd, 0, sizeof(PDF_FONTDATA)); + HDC hDC = ::GetDC(nullptr); + EnumFontFamiliesExA(hDC, &lf, (FONTENUMPROCA)EnumFontFamExProc, (LPARAM)&fd, + 0); + ::ReleaseDC(nullptr, hDC); + if (fd.bFind) + memcpy(&lf, &fd.lf, sizeof(LOGFONTA)); + + return fd.bFind; +} +#endif // BUILDFLAG(IS_WIN) + +ByteString GetNativeFontName(FX_Charset charSet, void* pLogFont) { + ByteString csFontName; +#if BUILDFLAG(IS_WIN) + LOGFONTA lf = {}; + if (charSet == FX_Charset::kANSI) { + csFontName = CFX_Font::kDefaultAnsiFontName; + return csFontName; + } + bool bRet = false; + const ByteString default_font_name = + CFX_Font::GetDefaultFontNameByCharset(charSet); + if (!default_font_name.IsEmpty()) + bRet = RetrieveSpecificFont(charSet, default_font_name.c_str(), lf); + if (!bRet) { + bRet = + RetrieveSpecificFont(charSet, CFX_Font::kUniversalDefaultFontName, lf); + } + if (!bRet) + bRet = RetrieveSpecificFont(charSet, "Microsoft Sans Serif", lf); + if (!bRet) + bRet = RetrieveSpecificFont(charSet, nullptr, lf); + if (bRet) { + if (pLogFont) + memcpy(pLogFont, &lf, sizeof(LOGFONTA)); + csFontName = lf.lfFaceName; + } +#endif + return csFontName; +} ByteString GenerateNewFontResourceName(const CPDF_Dictionary* pResDict, const ByteString& csPrefix) { @@ -58,8 +131,8 @@ m++; } - const CPDF_Dictionary* pDict = pResDict->GetDictFor("Font"); - ASSERT(pDict); + RetainPtr<const CPDF_Dictionary> pDict = pResDict->GetDictFor("Font"); + DCHECK(pDict); int num = 0; ByteString bsNum; @@ -67,146 +140,57 @@ ByteString csKey = csTmp + bsNum; if (!pDict->KeyExist(csKey)) return csKey; + if (m < szCount) csTmp += csStr[m++]; else - bsNum = ByteString::Format("%d", num++); - + bsNum = ByteString::FormatInteger(num++); m++; } - return csTmp; } -void InitDict(CPDF_Dictionary*& pFormDict, CPDF_Document* pDocument) { - if (!pDocument) - return; - - if (!pFormDict) { - pFormDict = pDocument->NewIndirect<CPDF_Dictionary>(); - pDocument->GetRoot()->SetNewFor<CPDF_Reference>("AcroForm", pDocument, - pFormDict->GetObjNum()); - } - - ByteString csDA; - if (!pFormDict->KeyExist("DR")) { - ByteString csBaseName; - uint8_t charSet = CPDF_InteractiveForm::GetNativeCharSet(); - RetainPtr<CPDF_Font> pFont = CPDF_InteractiveForm::AddStandardFont( - pDocument, CFX_Font::kDefaultAnsiFontName); - if (pFont) - AddFont(pFormDict, pDocument, pFont, &csBaseName); - - if (charSet != FX_CHARSET_ANSI) { - ByteString csFontName = - CPDF_InteractiveForm::GetNativeFontName(charSet, nullptr); - if (!pFont || csFontName != CFX_Font::kDefaultAnsiFontName) { - pFont = CPDF_InteractiveForm::AddNativeFont(pDocument); - if (pFont) { - csBaseName.clear(); - AddFont(pFormDict, pDocument, pFont, &csBaseName); - } - } - } - if (pFont) - csDA = "/" + PDF_NameEncode(csBaseName) + " 0 Tf"; - } - if (!csDA.IsEmpty()) - csDA += " "; - - csDA += "0 g"; - if (!pFormDict->KeyExist("DA")) - pFormDict->SetNewFor<CPDF_String>("DA", csDA, false); +RetainPtr<CPDF_Font> AddStandardFont(CPDF_Document* pDocument) { + auto* pPageData = CPDF_DocPageData::FromDocument(pDocument); + static const CPDF_FontEncoding encoding(FontEncoding::kWinAnsi); + return pPageData->AddStandardFont(CFX_Font::kDefaultAnsiFontName, &encoding); } -RetainPtr<CPDF_Font> GetFont(CPDF_Dictionary* pFormDict, - CPDF_Document* pDocument, - const ByteString& csNameTag) { - ByteString csAlias = PDF_NameDecode(csNameTag.AsStringView()); - if (!pFormDict || csAlias.IsEmpty()) - return nullptr; +RetainPtr<CPDF_Font> AddNativeFont(FX_Charset charSet, + CPDF_Document* pDocument) { + DCHECK(pDocument); - CPDF_Dictionary* pDR = pFormDict->GetDictFor("DR"); - if (!pDR) - return nullptr; - - CPDF_Dictionary* pFonts = pDR->GetDictFor("Font"); - if (!ValidateFontResourceDict(pFonts)) - return nullptr; - - CPDF_Dictionary* pElement = pFonts->GetDictFor(csAlias); - if (!pElement || pElement->GetStringFor("Type") != "Font") - return nullptr; - - return CPDF_DocPageData::FromDocument(pDocument)->GetFont(pElement); -} - -RetainPtr<CPDF_Font> GetNativeFont(CPDF_Dictionary* pFormDict, - CPDF_Document* pDocument, - uint8_t charSet, - ByteString* csNameTag) { - if (!pFormDict) - return nullptr; - - CPDF_Dictionary* pDR = pFormDict->GetDictFor("DR"); - if (!pDR) - return nullptr; - - CPDF_Dictionary* pFonts = pDR->GetDictFor("Font"); - if (!ValidateFontResourceDict(pFonts)) - return nullptr; - - CPDF_DictionaryLocker locker(pFonts); - for (const auto& it : locker) { - const ByteString& csKey = it.first; - if (!it.second) - continue; - - CPDF_Dictionary* pElement = ToDictionary(it.second->GetDirect()); - if (!pElement || pElement->GetStringFor("Type") != "Font") - continue; - - auto* pData = CPDF_DocPageData::FromDocument(pDocument); - RetainPtr<CPDF_Font> pFind = pData->GetFont(pElement); - if (!pFind) - continue; - - CFX_SubstFont* pSubst = pFind->GetSubstFont(); - if (!pSubst) - continue; - - if (pSubst->m_Charset == static_cast<int>(charSet)) { - *csNameTag = csKey; - return pFind; - } +#if BUILDFLAG(IS_WIN) + LOGFONTA lf; + ByteString csFontName = GetNativeFontName(charSet, &lf); + if (!csFontName.IsEmpty()) { + if (csFontName == CFX_Font::kDefaultAnsiFontName) + return AddStandardFont(pDocument); + return CPDF_DocPageData::FromDocument(pDocument)->AddWindowsFont(&lf); } +#endif return nullptr; } -bool FindFont(CPDF_Dictionary* pFormDict, +bool FindFont(const CPDF_Dictionary* pFormDict, const CPDF_Font* pFont, ByteString* csNameTag) { - if (!pFormDict || !pFont) - return false; - - CPDF_Dictionary* pDR = pFormDict->GetDictFor("DR"); + RetainPtr<const CPDF_Dictionary> pDR = pFormDict->GetDictFor("DR"); if (!pDR) return false; - CPDF_Dictionary* pFonts = pDR->GetDictFor("Font"); - if (!ValidateFontResourceDict(pFonts)) + RetainPtr<const CPDF_Dictionary> pFonts = pDR->GetDictFor("Font"); + // TODO(tsepez): this eventually locks the dict, pass locker instead. + if (!ValidateFontResourceDict(pFonts.Get())) return false; - CPDF_DictionaryLocker locker(pFonts); + CPDF_DictionaryLocker locker(std::move(pFonts)); for (const auto& it : locker) { const ByteString& csKey = it.first; - if (!it.second) + RetainPtr<const CPDF_Dictionary> pElement = + ToDictionary(it.second->GetDirect()); + if (!ValidateDictType(pElement.Get(), "Font")) continue; - CPDF_Dictionary* pElement = ToDictionary(it.second->GetDirect()); - if (!pElement) - continue; - if (pElement->GetStringFor("Type") != "Font") - continue; - if (pFont->GetFontDict() == pElement) { + if (pFont->FontDictIs(pElement)) { *csNameTag = csKey; return true; } @@ -214,36 +198,33 @@ return false; } -bool FindFont(CPDF_Dictionary* pFormDict, - CPDF_Document* pDocument, - ByteString csFontName, - RetainPtr<CPDF_Font>& pFont, - ByteString* csNameTag) { - if (!pFormDict) +bool FindFontFromDoc(const CPDF_Dictionary* pFormDict, + CPDF_Document* pDocument, + ByteString csFontName, + RetainPtr<CPDF_Font>& pFont, + ByteString* csNameTag) { + if (csFontName.IsEmpty()) return false; - CPDF_Dictionary* pDR = pFormDict->GetDictFor("DR"); + RetainPtr<const CPDF_Dictionary> pDR = pFormDict->GetDictFor("DR"); if (!pDR) return false; - CPDF_Dictionary* pFonts = pDR->GetDictFor("Font"); - if (!ValidateFontResourceDict(pFonts)) + RetainPtr<const CPDF_Dictionary> pFonts = pDR->GetDictFor("Font"); + if (!ValidateFontResourceDict(pFonts.Get())) return false; - if (csFontName.GetLength() > 0) - csFontName.Remove(' '); - + csFontName.Remove(' '); CPDF_DictionaryLocker locker(pFonts); for (const auto& it : locker) { const ByteString& csKey = it.first; - if (!it.second) + RetainPtr<CPDF_Dictionary> pElement = + ToDictionary(it.second->GetMutableDirect()); + if (!ValidateDictType(pElement.Get(), "Font")) continue; - CPDF_Dictionary* pElement = ToDictionary(it.second->GetDirect()); - if (!pElement || pElement->GetStringFor("Type") != "Font") - continue; - - pFont = CPDF_DocPageData::FromDocument(pDocument)->GetFont(pElement); + auto* pData = CPDF_DocPageData::FromDocument(pDocument); + pFont = pData->GetFont(std::move(pElement)); if (!pFont) continue; @@ -257,140 +238,120 @@ return false; } -void AddFont(CPDF_Dictionary*& pFormDict, +void AddFont(CPDF_Dictionary* pFormDict, CPDF_Document* pDocument, const RetainPtr<CPDF_Font>& pFont, ByteString* csNameTag) { - if (!pFont) - return; - if (!pFormDict) - InitDict(pFormDict, pDocument); + DCHECK(pFormDict); + DCHECK(pFont); ByteString csTag; if (FindFont(pFormDict, pFont.Get(), &csTag)) { *csNameTag = std::move(csTag); return; } - if (!pFormDict) - InitDict(pFormDict, pDocument); - CPDF_Dictionary* pDR = pFormDict->GetDictFor("DR"); - if (!pDR) - pDR = pFormDict->SetNewFor<CPDF_Dictionary>("DR"); - - CPDF_Dictionary* pFonts = pDR->GetDictFor("Font"); - if (!pFonts) - pFonts = pDR->SetNewFor<CPDF_Dictionary>("Font"); + RetainPtr<CPDF_Dictionary> pDR = pFormDict->GetOrCreateDictFor("DR"); + RetainPtr<CPDF_Dictionary> pFonts = pDR->GetOrCreateDictFor("Font"); if (csNameTag->IsEmpty()) *csNameTag = pFont->GetBaseFontName(); csNameTag->Remove(' '); - *csNameTag = GenerateNewFontResourceName(pDR, *csNameTag); + *csNameTag = GenerateNewFontResourceName(pDR.Get(), *csNameTag); pFonts->SetNewFor<CPDF_Reference>(*csNameTag, pDocument, - pFont->GetFontDict()->GetObjNum()); + pFont->GetFontDictObjNum()); } -RetainPtr<CPDF_Font> AddNativeFont(CPDF_Dictionary*& pFormDict, - CPDF_Document* pDocument, - uint8_t charSet, - ByteString* csNameTag) { - if (!pFormDict) - InitDict(pFormDict, pDocument); +FX_Charset GetNativeCharSet() { + return FX_GetCharsetFromCodePage(FX_GetACP()); +} - ByteString csTemp; - RetainPtr<CPDF_Font> pFont = - GetNativeFont(pFormDict, pDocument, charSet, &csTemp); +RetainPtr<CPDF_Dictionary> InitDict(CPDF_Document* pDocument) { + auto pFormDict = pDocument->NewIndirect<CPDF_Dictionary>(); + pDocument->GetMutableRoot()->SetNewFor<CPDF_Reference>( + "AcroForm", pDocument, pFormDict->GetObjNum()); + + ByteString csBaseName; + FX_Charset charSet = GetNativeCharSet(); + RetainPtr<CPDF_Font> pFont = AddStandardFont(pDocument); if (pFont) { - *csNameTag = std::move(csTemp); - return pFont; + AddFont(pFormDict.Get(), pDocument, pFont, &csBaseName); } - ByteString csFontName = - CPDF_InteractiveForm::GetNativeFontName(charSet, nullptr); - if (!csFontName.IsEmpty() && - FindFont(pFormDict, pDocument, csFontName, pFont, csNameTag)) { - return pFont; + if (charSet != FX_Charset::kANSI) { + ByteString csFontName = GetNativeFontName(charSet, nullptr); + if (!pFont || csFontName != CFX_Font::kDefaultAnsiFontName) { + pFont = AddNativeFont(charSet, pDocument); + if (pFont) { + csBaseName.clear(); + AddFont(pFormDict.Get(), pDocument, pFont, &csBaseName); + } + } } - pFont = CPDF_InteractiveForm::AddNativeFont(charSet, pDocument); - if (!pFont) + ByteString csDA; + if (pFont) + csDA = "/" + PDF_NameEncode(csBaseName) + " 0 Tf "; + csDA += "0 g"; + pFormDict->SetNewFor<CPDF_String>("DA", csDA, /*bHex=*/false); + return pFormDict; +} + +RetainPtr<CPDF_Font> GetNativeFont(const CPDF_Dictionary* pFormDict, + CPDF_Document* pDocument, + FX_Charset charSet, + ByteString* csNameTag) { + RetainPtr<const CPDF_Dictionary> pDR = pFormDict->GetDictFor("DR"); + if (!pDR) return nullptr; - AddFont(pFormDict, pDocument, pFont, csNameTag); - return pFont; + RetainPtr<const CPDF_Dictionary> pFonts = pDR->GetDictFor("Font"); + if (!ValidateFontResourceDict(pFonts.Get())) + return nullptr; + + CPDF_DictionaryLocker locker(pFonts); + for (const auto& it : locker) { + const ByteString& csKey = it.first; + RetainPtr<CPDF_Dictionary> pElement = + ToDictionary(it.second->GetMutableDirect()); + if (!ValidateDictType(pElement.Get(), "Font")) + continue; + + auto* pData = CPDF_DocPageData::FromDocument(pDocument); + RetainPtr<CPDF_Font> pFind = pData->GetFont(std::move(pElement)); + if (!pFind) + continue; + + auto maybe_charset = pFind->GetSubstFontCharset(); + if (maybe_charset.has_value() && maybe_charset.value() == charSet) { + *csNameTag = csKey; + return pFind; + } + } + return nullptr; } class CFieldNameExtractor { public: explicit CFieldNameExtractor(const WideString& full_name) - : m_FullName(full_name) { - m_pCur = m_FullName.c_str(); - m_pEnd = m_pCur + m_FullName.GetLength(); - } + : m_FullName(full_name) {} - void GetNext(const wchar_t*& pSubName, size_t& size) { - pSubName = m_pCur; - while (m_pCur < m_pEnd && m_pCur[0] != L'.') - m_pCur++; + WideStringView GetNext() { + size_t start_pos = m_iCur; + while (m_iCur < m_FullName.GetLength() && m_FullName[m_iCur] != L'.') + ++m_iCur; - size = static_cast<size_t>(m_pCur - pSubName); - if (m_pCur < m_pEnd && m_pCur[0] == L'.') - m_pCur++; + size_t length = m_iCur - start_pos; + if (m_iCur < m_FullName.GetLength() && m_FullName[m_iCur] == L'.') + ++m_iCur; + + return m_FullName.AsStringView().Substr(start_pos, length); } protected: - WideString m_FullName; - const wchar_t* m_pCur; - const wchar_t* m_pEnd; + const WideString m_FullName; + size_t m_iCur = 0; }; -#if defined(OS_WIN) -struct PDF_FONTDATA { - bool bFind; - LOGFONTA lf; -}; - -static int CALLBACK EnumFontFamExProc(ENUMLOGFONTEXA* lpelfe, - NEWTEXTMETRICEX* lpntme, - DWORD FontType, - LPARAM lParam) { - if (FontType != 0x004 || strchr(lpelfe->elfLogFont.lfFaceName, '@')) - return 1; - - PDF_FONTDATA* pData = (PDF_FONTDATA*)lParam; - memcpy(&pData->lf, &lpelfe->elfLogFont, sizeof(LOGFONTA)); - pData->bFind = true; - return 0; -} - -bool RetrieveSpecificFont(LOGFONTA& lf) { - PDF_FONTDATA fd; - memset(&fd, 0, sizeof(PDF_FONTDATA)); - HDC hDC = ::GetDC(nullptr); - EnumFontFamiliesExA(hDC, &lf, (FONTENUMPROCA)EnumFontFamExProc, (LPARAM)&fd, - 0); - ::ReleaseDC(nullptr, hDC); - if (fd.bFind) - memcpy(&lf, &fd.lf, sizeof(LOGFONTA)); - - return fd.bFind; -} - -bool RetrieveSpecificFont(uint8_t charSet, - uint8_t pitchAndFamily, - LPCSTR pcsFontName, - LOGFONTA& lf) { - memset(&lf, 0, sizeof(LOGFONTA)); - lf.lfCharSet = charSet; - lf.lfPitchAndFamily = pitchAndFamily; - if (pcsFontName) { - // TODO(dsinclair): Should this be strncpy? - // NOLINTNEXTLINE(runtime/printf) - strcpy(lf.lfFaceName, pcsFontName); - } - return RetrieveSpecificFont(lf); -} -#endif // defined(OS_WIN) - } // namespace class CFieldTree { @@ -465,15 +426,16 @@ std::unique_ptr<CPDF_FormField> pField); CPDF_FormField* GetField(const WideString& full_name); + Node* GetRoot() { return m_pRoot.get(); } Node* FindNode(const WideString& full_name); Node* AddChild(Node* pParent, const WideString& short_name); + Node* Lookup(Node* pParent, WideStringView short_name); - Node* Lookup(Node* pParent, const WideString& short_name); - - Node m_Root; + private: + std::unique_ptr<Node> m_pRoot; }; -CFieldTree::CFieldTree() = default; +CFieldTree::CFieldTree() : m_pRoot(std::make_unique<Node>()) {} CFieldTree::~CFieldTree() = default; @@ -486,14 +448,13 @@ if (level > nMaxRecursion) return nullptr; - auto pNew = pdfium::MakeUnique<Node>(short_name, pParent->GetLevel() + 1); + auto pNew = std::make_unique<Node>(short_name, pParent->GetLevel() + 1); Node* pChild = pNew.get(); pParent->AddChildNode(std::move(pNew)); return pChild; } -CFieldTree::Node* CFieldTree::Lookup(Node* pParent, - const WideString& short_name) { +CFieldTree::Node* CFieldTree::Lookup(Node* pParent, WideStringView short_name) { if (!pParent) return nullptr; @@ -510,24 +471,22 @@ if (full_name.IsEmpty()) return false; - CFieldNameExtractor name_extractor(full_name); - const wchar_t* pName; - size_t nLength; - name_extractor.GetNext(pName, nLength); - Node* pNode = &m_Root; + Node* pNode = GetRoot(); Node* pLast = nullptr; - while (nLength > 0) { + CFieldNameExtractor name_extractor(full_name); + while (true) { + WideStringView name_view = name_extractor.GetNext(); + if (name_view.IsEmpty()) + break; pLast = pNode; - WideString name = WideString(pName, nLength); - pNode = Lookup(pLast, name); - if (!pNode) - pNode = AddChild(pLast, name); + pNode = Lookup(pLast, name_view); + if (pNode) + continue; + pNode = AddChild(pLast, WideString(name_view)); if (!pNode) return false; - - name_extractor.GetNext(pName, nLength); } - if (pNode == &m_Root) + if (pNode == GetRoot()) return false; pNode->SetField(std::move(pField)); @@ -538,17 +497,15 @@ if (full_name.IsEmpty()) return nullptr; - CFieldNameExtractor name_extractor(full_name); - const wchar_t* pName; - size_t nLength; - name_extractor.GetNext(pName, nLength); - Node* pNode = &m_Root; + Node* pNode = GetRoot(); Node* pLast = nullptr; - while (nLength > 0 && pNode) { + CFieldNameExtractor name_extractor(full_name); + while (pNode) { + WideStringView name_view = name_extractor.GetNext(); + if (name_view.IsEmpty()) + break; pLast = pNode; - WideString name = WideString(pName, nLength); - pNode = Lookup(pLast, name); - name_extractor.GetNext(pName, nLength); + pNode = Lookup(pLast, name_view); } return pNode ? pNode->GetField() : nullptr; } @@ -557,159 +514,103 @@ if (full_name.IsEmpty()) return nullptr; - CFieldNameExtractor name_extractor(full_name); - const wchar_t* pName; - size_t nLength; - name_extractor.GetNext(pName, nLength); - Node* pNode = &m_Root; + Node* pNode = GetRoot(); Node* pLast = nullptr; - while (nLength > 0 && pNode) { + CFieldNameExtractor name_extractor(full_name); + while (pNode) { + WideStringView name_view = name_extractor.GetNext(); + if (name_view.IsEmpty()) + break; pLast = pNode; - WideString name = WideString(pName, nLength); - pNode = Lookup(pLast, name); - name_extractor.GetNext(pName, nLength); + pNode = Lookup(pLast, name_view); } return pNode; } -RetainPtr<CPDF_Font> AddNativeInteractiveFormFont(CPDF_Dictionary*& pFormDict, - CPDF_Document* pDocument, - ByteString* csNameTag) { - uint8_t charSet = CPDF_InteractiveForm::GetNativeCharSet(); - return AddNativeFont(pFormDict, pDocument, charSet, csNameTag); -} - -// static -uint8_t CPDF_InteractiveForm::GetNativeCharSet() { - return FX_GetCharsetFromCodePage(FXSYS_GetACP()); -} - CPDF_InteractiveForm::CPDF_InteractiveForm(CPDF_Document* pDocument) - : m_pDocument(pDocument), m_pFieldTree(pdfium::MakeUnique<CFieldTree>()) { - CPDF_Dictionary* pRoot = m_pDocument->GetRoot(); + : m_pDocument(pDocument), m_pFieldTree(std::make_unique<CFieldTree>()) { + RetainPtr<CPDF_Dictionary> pRoot = m_pDocument->GetMutableRoot(); if (!pRoot) return; - m_pFormDict.Reset(pRoot->GetDictFor("AcroForm")); + m_pFormDict = pRoot->GetMutableDictFor("AcroForm"); if (!m_pFormDict) return; - CPDF_Array* pFields = m_pFormDict->GetArrayFor("Fields"); + RetainPtr<CPDF_Array> pFields = m_pFormDict->GetMutableArrayFor("Fields"); if (!pFields) return; for (size_t i = 0; i < pFields->size(); ++i) - LoadField(pFields->GetDictAt(i), 0); + LoadField(pFields->GetMutableDictAt(i), 0); } CPDF_InteractiveForm::~CPDF_InteractiveForm() = default; bool CPDF_InteractiveForm::s_bUpdateAP = true; +// static bool CPDF_InteractiveForm::IsUpdateAPEnabled() { return s_bUpdateAP; } +// static void CPDF_InteractiveForm::SetUpdateAP(bool bUpdateAP) { s_bUpdateAP = bUpdateAP; } -RetainPtr<CPDF_Font> CPDF_InteractiveForm::AddStandardFont( +// static +RetainPtr<CPDF_Font> CPDF_InteractiveForm::AddNativeInteractiveFormFont( CPDF_Document* pDocument, - ByteString csFontName) { - if (!pDocument || csFontName.IsEmpty()) + ByteString* csNameTag) { + DCHECK(pDocument); + DCHECK(csNameTag); + + RetainPtr<CPDF_Dictionary> pFormDict = + pDocument->GetMutableRoot()->GetMutableDictFor("AcroForm"); + if (!pFormDict) + pFormDict = InitDict(pDocument); + + FX_Charset charSet = GetNativeCharSet(); + ByteString csTemp; + RetainPtr<CPDF_Font> pFont = + GetNativeFont(pFormDict.Get(), pDocument, charSet, &csTemp); + if (pFont) { + *csNameTag = std::move(csTemp); + return pFont; + } + ByteString csFontName = GetNativeFontName(charSet, nullptr); + if (FindFontFromDoc(pFormDict.Get(), pDocument, csFontName, pFont, csNameTag)) + return pFont; + + pFont = AddNativeFont(charSet, pDocument); + if (!pFont) return nullptr; - auto* pPageData = CPDF_DocPageData::FromDocument(pDocument); - if (csFontName == "ZapfDingbats") - return pPageData->AddStandardFont(csFontName, nullptr); - - static const CPDF_FontEncoding encoding(PDFFONT_ENCODING_WINANSI); - return pPageData->AddStandardFont(csFontName, &encoding); -} - -ByteString CPDF_InteractiveForm::GetNativeFontName(uint8_t charSet, - void* pLogFont) { - ByteString csFontName; -#if defined(OS_WIN) - LOGFONTA lf = {}; - if (charSet == FX_CHARSET_ANSI) { - csFontName = CFX_Font::kDefaultAnsiFontName; - return csFontName; - } - bool bRet = false; - const ByteString default_font_name = - CFX_Font::GetDefaultFontNameByCharset(charSet); - if (!default_font_name.IsEmpty()) { - bRet = RetrieveSpecificFont(charSet, DEFAULT_PITCH | FF_DONTCARE, - default_font_name.c_str(), lf); - } - if (!bRet) { - bRet = RetrieveSpecificFont(charSet, DEFAULT_PITCH | FF_DONTCARE, - CFX_Font::kUniversalDefaultFontName, lf); - } - if (!bRet) { - bRet = RetrieveSpecificFont(charSet, DEFAULT_PITCH | FF_DONTCARE, - "Microsoft Sans Serif", lf); - } - if (!bRet) { - bRet = - RetrieveSpecificFont(charSet, DEFAULT_PITCH | FF_DONTCARE, nullptr, lf); - } - if (bRet) { - if (pLogFont) - memcpy(pLogFont, &lf, sizeof(LOGFONTA)); - - csFontName = lf.lfFaceName; - return csFontName; - } -#endif - return csFontName; -} - -RetainPtr<CPDF_Font> CPDF_InteractiveForm::AddNativeFont( - uint8_t charSet, - CPDF_Document* pDocument) { - if (!pDocument) - return nullptr; - -#if defined(OS_WIN) - LOGFONTA lf; - ByteString csFontName = GetNativeFontName(charSet, &lf); - if (!csFontName.IsEmpty()) { - if (csFontName == CFX_Font::kDefaultAnsiFontName) - return AddStandardFont(pDocument, csFontName); - return CPDF_DocPageData::FromDocument(pDocument)->AddWindowsFont(&lf); - } -#endif - return nullptr; -} - -RetainPtr<CPDF_Font> CPDF_InteractiveForm::AddNativeFont( - CPDF_Document* pDocument) { - return pDocument ? AddNativeFont(GetNativeCharSet(), pDocument) : nullptr; + AddFont(pFormDict.Get(), pDocument, pFont, csNameTag); + return pFont; } size_t CPDF_InteractiveForm::CountFields(const WideString& csFieldName) const { if (csFieldName.IsEmpty()) - return m_pFieldTree->m_Root.CountFields(); + return m_pFieldTree->GetRoot()->CountFields(); CFieldTree::Node* pNode = m_pFieldTree->FindNode(csFieldName); return pNode ? pNode->CountFields() : 0; } CPDF_FormField* CPDF_InteractiveForm::GetField( - uint32_t index, + size_t index, const WideString& csFieldName) const { if (csFieldName.IsEmpty()) - return m_pFieldTree->m_Root.GetFieldAtIndex(index); + return m_pFieldTree->GetRoot()->GetFieldAtIndex(index); CFieldTree::Node* pNode = m_pFieldTree->FindNode(csFieldName); return pNode ? pNode->GetFieldAtIndex(index) : nullptr; } CPDF_FormField* CPDF_InteractiveForm::GetFieldByDict( - CPDF_Dictionary* pFieldDict) const { + const CPDF_Dictionary* pFieldDict) const { if (!pFieldDict) return nullptr; @@ -717,26 +618,26 @@ return m_pFieldTree->GetField(csWName); } -CPDF_FormControl* CPDF_InteractiveForm::GetControlAtPoint( - CPDF_Page* pPage, +const CPDF_FormControl* CPDF_InteractiveForm::GetControlAtPoint( + const CPDF_Page* pPage, const CFX_PointF& point, - int* z_order) const { - CPDF_Array* pAnnotList = pPage->GetDict()->GetArrayFor("Annots"); + RetainPtr<const CPDF_Array> pAnnotList = pPage->GetAnnotsArray(); if (!pAnnotList) return nullptr; for (size_t i = pAnnotList->size(); i > 0; --i) { size_t annot_index = i - 1; - const CPDF_Dictionary* pAnnot = pAnnotList->GetDictAt(annot_index); + RetainPtr<const CPDF_Dictionary> pAnnot = + pAnnotList->GetDictAt(annot_index); if (!pAnnot) continue; - const auto it = m_ControlMap.find(pAnnot); + const auto it = m_ControlMap.find(pAnnot.Get()); if (it == m_ControlMap.end()) continue; - CPDF_FormControl* pControl = it->second.get(); + const CPDF_FormControl* pControl = it->second.get(); if (!pControl->GetRect().Contains(point)) continue; @@ -761,156 +662,165 @@ if (!m_pFormDict) return 0; - CPDF_Array* pArray = m_pFormDict->GetArrayFor("CO"); - return pArray ? pArray->size() : 0; + RetainPtr<const CPDF_Array> pArray = m_pFormDict->GetArrayFor("CO"); + return pArray ? fxcrt::CollectionSize<int>(*pArray) : 0; } CPDF_FormField* CPDF_InteractiveForm::GetFieldInCalculationOrder(int index) { if (!m_pFormDict || index < 0) return nullptr; - CPDF_Array* pArray = m_pFormDict->GetArrayFor("CO"); + RetainPtr<const CPDF_Array> pArray = m_pFormDict->GetArrayFor("CO"); if (!pArray) return nullptr; - CPDF_Dictionary* pElement = ToDictionary(pArray->GetDirectObjectAt(index)); - return pElement ? GetFieldByDict(pElement) : nullptr; + RetainPtr<const CPDF_Dictionary> pElement = + ToDictionary(pArray->GetDirectObjectAt(index)); + return pElement ? GetFieldByDict(pElement.Get()) : nullptr; } int CPDF_InteractiveForm::FindFieldInCalculationOrder( const CPDF_FormField* pField) { - if (!m_pFormDict || !pField) + if (!m_pFormDict) return -1; - CPDF_Array* pArray = m_pFormDict->GetArrayFor("CO"); + RetainPtr<const CPDF_Array> pArray = m_pFormDict->GetArrayFor("CO"); if (!pArray) return -1; - for (size_t i = 0; i < pArray->size(); i++) { - CPDF_Object* pElement = pArray->GetDirectObjectAt(i); - if (pElement == pField->GetDict()) - return i; - } - return -1; + absl::optional<size_t> maybe_found = pArray->Find(pField->GetFieldDict()); + if (!maybe_found.has_value()) + return -1; + + return pdfium::base::checked_cast<int>(maybe_found.value()); } RetainPtr<CPDF_Font> CPDF_InteractiveForm::GetFormFont( ByteString csNameTag) const { - return GetFont(m_pFormDict.Get(), m_pDocument.Get(), csNameTag); + ByteString csAlias = PDF_NameDecode(csNameTag.AsStringView()); + if (!m_pFormDict || csAlias.IsEmpty()) + return nullptr; + + RetainPtr<CPDF_Dictionary> pDR = m_pFormDict->GetMutableDictFor("DR"); + if (!pDR) + return nullptr; + + RetainPtr<CPDF_Dictionary> pFonts = pDR->GetMutableDictFor("Font"); + if (!ValidateFontResourceDict(pFonts.Get())) + return nullptr; + + RetainPtr<CPDF_Dictionary> pElement = pFonts->GetMutableDictFor(csAlias); + if (!ValidateDictType(pElement.Get(), "Font")) + return nullptr; + + return GetFontForElement(std::move(pElement)); +} + +RetainPtr<CPDF_Font> CPDF_InteractiveForm::GetFontForElement( + RetainPtr<CPDF_Dictionary> pElement) const { + auto* pData = CPDF_DocPageData::FromDocument(m_pDocument); + return pData->GetFont(std::move(pElement)); } CPDF_DefaultAppearance CPDF_InteractiveForm::GetDefaultAppearance() const { if (!m_pFormDict) return CPDF_DefaultAppearance(); - return CPDF_DefaultAppearance(m_pFormDict->GetStringFor("DA")); + return CPDF_DefaultAppearance(m_pFormDict->GetByteStringFor("DA")); } int CPDF_InteractiveForm::GetFormAlignment() const { return m_pFormDict ? m_pFormDict->GetIntegerFor("Q", 0) : 0; } -void CPDF_InteractiveForm::ResetForm(const std::vector<CPDF_FormField*>& fields, - bool bIncludeOrExclude, - NotificationOption notify) { - size_t nCount = m_pFieldTree->m_Root.CountFields(); +void CPDF_InteractiveForm::ResetForm(pdfium::span<CPDF_FormField*> fields, + bool bIncludeOrExclude) { + CFieldTree::Node* pRoot = m_pFieldTree->GetRoot(); + const size_t nCount = pRoot->CountFields(); for (size_t i = 0; i < nCount; ++i) { - CPDF_FormField* pField = m_pFieldTree->m_Root.GetFieldAtIndex(i); + CPDF_FormField* pField = pRoot->GetFieldAtIndex(i); if (!pField) continue; - if (bIncludeOrExclude == pdfium::ContainsValue(fields, pField)) - pField->ResetField(notify); + if (bIncludeOrExclude == pdfium::Contains(fields, pField)) + pField->ResetField(); } - if (notify == NotificationOption::kNotify && m_pFormNotify) + if (m_pFormNotify) m_pFormNotify->AfterFormReset(this); } -void CPDF_InteractiveForm::ResetForm(NotificationOption notify) { - size_t nCount = m_pFieldTree->m_Root.CountFields(); - for (size_t i = 0; i < nCount; ++i) { - CPDF_FormField* pField = m_pFieldTree->m_Root.GetFieldAtIndex(i); - if (!pField) - continue; - - pField->ResetField(notify); - } - if (notify == NotificationOption::kNotify && m_pFormNotify) - m_pFormNotify->AfterFormReset(this); +void CPDF_InteractiveForm::ResetForm() { + ResetForm(/*fields=*/{}, /*bIncludeOrExclude=*/false); } const std::vector<UnownedPtr<CPDF_FormControl>>& CPDF_InteractiveForm::GetControlsForField(const CPDF_FormField* pField) { - return m_ControlLists[pField]; + return m_ControlLists[pdfium::WrapUnowned(pField)]; } -void CPDF_InteractiveForm::LoadField(CPDF_Dictionary* pFieldDict, int nLevel) { +void CPDF_InteractiveForm::LoadField(RetainPtr<CPDF_Dictionary> pFieldDict, + int nLevel) { if (nLevel > nMaxRecursion) return; if (!pFieldDict) return; uint32_t dwParentObjNum = pFieldDict->GetObjNum(); - CPDF_Array* pKids = pFieldDict->GetArrayFor(pdfium::form_fields::kKids); + RetainPtr<CPDF_Array> pKids = + pFieldDict->GetMutableArrayFor(pdfium::form_fields::kKids); if (!pKids) { - AddTerminalField(pFieldDict); + AddTerminalField(std::move(pFieldDict)); return; } - CPDF_Dictionary* pFirstKid = pKids->GetDictAt(0); + RetainPtr<const CPDF_Dictionary> pFirstKid = pKids->GetDictAt(0); if (!pFirstKid) return; - if (pFirstKid->KeyExist(pdfium::form_fields::kT) || - pFirstKid->KeyExist(pdfium::form_fields::kKids)) { - for (size_t i = 0; i < pKids->size(); i++) { - CPDF_Dictionary* pChildDict = pKids->GetDictAt(i); - if (pChildDict) { - if (pChildDict->GetObjNum() != dwParentObjNum) - LoadField(pChildDict, nLevel + 1); - } - } - } else { - AddTerminalField(pFieldDict); + if (!pFirstKid->KeyExist(pdfium::form_fields::kT) && + !pFirstKid->KeyExist(pdfium::form_fields::kKids)) { + AddTerminalField(std::move(pFieldDict)); + return; + } + for (size_t i = 0; i < pKids->size(); i++) { + RetainPtr<CPDF_Dictionary> pChildDict = pKids->GetMutableDictAt(i); + if (pChildDict && pChildDict->GetObjNum() != dwParentObjNum) + LoadField(std::move(pChildDict), nLevel + 1); } } -bool CPDF_InteractiveForm::HasXFAForm() const { - return m_pFormDict && m_pFormDict->GetArrayFor("XFA"); -} - void CPDF_InteractiveForm::FixPageFields(CPDF_Page* pPage) { - CPDF_Array* pAnnots = pPage->GetDict()->GetArrayFor("Annots"); + RetainPtr<CPDF_Array> pAnnots = pPage->GetMutableAnnotsArray(); if (!pAnnots) return; for (size_t i = 0; i < pAnnots->size(); i++) { - CPDF_Dictionary* pAnnot = pAnnots->GetDictAt(i); - if (pAnnot && pAnnot->GetStringFor("Subtype") == "Widget") - LoadField(pAnnot, 0); + RetainPtr<CPDF_Dictionary> pAnnot = pAnnots->GetMutableDictAt(i); + if (pAnnot && pAnnot->GetNameFor("Subtype") == "Widget") + LoadField(std::move(pAnnot), 0); } } -void CPDF_InteractiveForm::AddTerminalField(CPDF_Dictionary* pFieldDict) { +void CPDF_InteractiveForm::AddTerminalField( + RetainPtr<CPDF_Dictionary> pFieldDict) { if (!pFieldDict->KeyExist(pdfium::form_fields::kFT)) { // Key "FT" is required for terminal fields, it is also inheritable. - CPDF_Dictionary* pParentDict = + RetainPtr<const CPDF_Dictionary> pParentDict = pFieldDict->GetDictFor(pdfium::form_fields::kParent); if (!pParentDict || !pParentDict->KeyExist(pdfium::form_fields::kFT)) return; } - CPDF_Dictionary* pDict = pFieldDict; - WideString csWName = CPDF_FormField::GetFullNameForDict(pFieldDict); + WideString csWName = CPDF_FormField::GetFullNameForDict(pFieldDict.Get()); if (csWName.IsEmpty()) return; CPDF_FormField* pField = nullptr; pField = m_pFieldTree->GetField(csWName); if (!pField) { - CPDF_Dictionary* pParent = pFieldDict; + RetainPtr<CPDF_Dictionary> pParent(pFieldDict); if (!pFieldDict->KeyExist(pdfium::form_fields::kT) && - pFieldDict->GetStringFor("Subtype") == "Widget") { - pParent = pFieldDict->GetDictFor(pdfium::form_fields::kParent); + pFieldDict->GetNameFor("Subtype") == "Widget") { + pParent = pFieldDict->GetMutableDictFor(pdfium::form_fields::kParent); if (!pParent) pParent = pFieldDict; } @@ -918,71 +828,71 @@ if (pParent && pParent != pFieldDict && !pParent->KeyExist(pdfium::form_fields::kFT)) { if (pFieldDict->KeyExist(pdfium::form_fields::kFT)) { - CPDF_Object* pFTValue = + RetainPtr<const CPDF_Object> pFTValue = pFieldDict->GetDirectObjectFor(pdfium::form_fields::kFT); if (pFTValue) pParent->SetFor(pdfium::form_fields::kFT, pFTValue->Clone()); } if (pFieldDict->KeyExist(pdfium::form_fields::kFf)) { - CPDF_Object* pFfValue = + RetainPtr<const CPDF_Object> pFfValue = pFieldDict->GetDirectObjectFor(pdfium::form_fields::kFf); if (pFfValue) pParent->SetFor(pdfium::form_fields::kFf, pFfValue->Clone()); } } - auto newField = pdfium::MakeUnique<CPDF_FormField>(this, pParent); + auto newField = std::make_unique<CPDF_FormField>(this, std::move(pParent)); pField = newField.get(); - CPDF_Object* pTObj = pDict->GetObjectFor(pdfium::form_fields::kT); + RetainPtr<const CPDF_Object> pTObj = + pFieldDict->GetObjectFor(pdfium::form_fields::kT); if (ToReference(pTObj)) { RetainPtr<CPDF_Object> pClone = pTObj->CloneDirectObject(); if (pClone) - pDict->SetFor(pdfium::form_fields::kT, std::move(pClone)); + pFieldDict->SetFor(pdfium::form_fields::kT, std::move(pClone)); else - pDict->SetNewFor<CPDF_Name>(pdfium::form_fields::kT, ByteString()); + pFieldDict->SetNewFor<CPDF_Name>(pdfium::form_fields::kT, ByteString()); } if (!m_pFieldTree->SetField(csWName, std::move(newField))) return; } - CPDF_Array* pKids = pFieldDict->GetArrayFor(pdfium::form_fields::kKids); - if (pKids) { - for (size_t i = 0; i < pKids->size(); i++) { - CPDF_Dictionary* pKid = pKids->GetDictAt(i); - if (!pKid) - continue; - if (pKid->GetStringFor("Subtype") != "Widget") - continue; - - AddControl(pField, pKid); - } - } else { - if (pFieldDict->GetStringFor("Subtype") == "Widget") - AddControl(pField, pFieldDict); + RetainPtr<CPDF_Array> pKids = + pFieldDict->GetMutableArrayFor(pdfium::form_fields::kKids); + if (!pKids) { + if (pFieldDict->GetNameFor("Subtype") == "Widget") + AddControl(pField, std::move(pFieldDict)); + return; + } + for (size_t i = 0; i < pKids->size(); i++) { + RetainPtr<CPDF_Dictionary> pKid = pKids->GetMutableDictAt(i); + if (pKid && pKid->GetNameFor("Subtype") == "Widget") + AddControl(pField, std::move(pKid)); } } CPDF_FormControl* CPDF_InteractiveForm::AddControl( CPDF_FormField* pField, - CPDF_Dictionary* pWidgetDict) { - const auto it = m_ControlMap.find(pWidgetDict); + RetainPtr<CPDF_Dictionary> pWidgetDict) { + DCHECK(pWidgetDict); + const auto it = m_ControlMap.find(pWidgetDict.Get()); if (it != m_ControlMap.end()) return it->second.get(); - auto pNew = pdfium::MakeUnique<CPDF_FormControl>(pField, pWidgetDict); + auto pNew = std::make_unique<CPDF_FormControl>(pField, pWidgetDict, this); CPDF_FormControl* pControl = pNew.get(); m_ControlMap[pWidgetDict] = std::move(pNew); - m_ControlLists[pField].emplace_back(pControl); + m_ControlLists[pdfium::WrapUnowned(pField)].emplace_back(pControl); return pControl; } bool CPDF_InteractiveForm::CheckRequiredFields( const std::vector<CPDF_FormField*>* fields, bool bIncludeOrExclude) const { - size_t nCount = m_pFieldTree->m_Root.CountFields(); + CFieldTree::Node* pRoot = m_pFieldTree->GetRoot(); + const size_t nCount = pRoot->CountFields(); for (size_t i = 0; i < nCount; ++i) { - CPDF_FormField* pField = m_pFieldTree->m_Root.GetFieldAtIndex(i); + CPDF_FormField* pField = pRoot->GetFieldAtIndex(i); if (!pField) continue; @@ -997,11 +907,11 @@ bool bFind = true; if (fields) - bFind = pdfium::ContainsValue(*fields, pField); + bFind = pdfium::Contains(*fields, pField); if (bIncludeOrExclude == bFind) { - const CPDF_Dictionary* pFieldDict = pField->GetDict(); + RetainPtr<const CPDF_Dictionary> pFieldDict = pField->GetFieldDict(); if (pField->IsRequired() && - pFieldDict->GetStringFor(pdfium::form_fields::kV).IsEmpty()) { + pFieldDict->GetByteStringFor(pdfium::form_fields::kV).IsEmpty()) { return false; } } @@ -1010,69 +920,67 @@ } std::unique_ptr<CFDF_Document> CPDF_InteractiveForm::ExportToFDF( - const WideString& pdf_path, - bool bSimpleFileSpec) const { + const WideString& pdf_path) const { std::vector<CPDF_FormField*> fields; - size_t nCount = m_pFieldTree->m_Root.CountFields(); + CFieldTree::Node* pRoot = m_pFieldTree->GetRoot(); + const size_t nCount = pRoot->CountFields(); for (size_t i = 0; i < nCount; ++i) - fields.push_back(m_pFieldTree->m_Root.GetFieldAtIndex(i)); - return ExportToFDF(pdf_path, fields, true, bSimpleFileSpec); + fields.push_back(pRoot->GetFieldAtIndex(i)); + return ExportToFDF(pdf_path, fields, true); } std::unique_ptr<CFDF_Document> CPDF_InteractiveForm::ExportToFDF( const WideString& pdf_path, const std::vector<CPDF_FormField*>& fields, - bool bIncludeOrExclude, - bool bSimpleFileSpec) const { + bool bIncludeOrExclude) const { std::unique_ptr<CFDF_Document> pDoc = CFDF_Document::CreateNewDoc(); if (!pDoc) return nullptr; - CPDF_Dictionary* pMainDict = pDoc->GetRoot()->GetDictFor("FDF"); + RetainPtr<CPDF_Dictionary> pMainDict = + pDoc->GetMutableRoot()->GetMutableDictFor("FDF"); if (!pdf_path.IsEmpty()) { - if (bSimpleFileSpec) { - WideString wsFilePath = CPDF_FileSpec::EncodeFileName(pdf_path); - pMainDict->SetNewFor<CPDF_String>(pdfium::stream::kF, - wsFilePath.ToDefANSI(), false); - pMainDict->SetNewFor<CPDF_String>("UF", wsFilePath); - } else { - auto pNewDict = pDoc->New<CPDF_Dictionary>(); - pNewDict->SetNewFor<CPDF_Name>("Type", "Filespec"); - CPDF_FileSpec filespec(pNewDict.Get()); - filespec.SetFileName(pdf_path); - pMainDict->SetFor("F", pNewDict); - } + auto pNewDict = pDoc->New<CPDF_Dictionary>(); + pNewDict->SetNewFor<CPDF_Name>("Type", "Filespec"); + WideString wsStr = CPDF_FileSpec::EncodeFileName(pdf_path); + pNewDict->SetNewFor<CPDF_String>(pdfium::stream::kF, wsStr.ToDefANSI(), + false); + pNewDict->SetNewFor<CPDF_String>("UF", wsStr.AsStringView()); + pMainDict->SetFor("F", pNewDict); } - CPDF_Array* pFields = pMainDict->SetNewFor<CPDF_Array>("Fields"); - size_t nCount = m_pFieldTree->m_Root.CountFields(); + auto pFields = pMainDict->SetNewFor<CPDF_Array>("Fields"); + CFieldTree::Node* pRoot = m_pFieldTree->GetRoot(); + const size_t nCount = pRoot->CountFields(); for (size_t i = 0; i < nCount; ++i) { - CPDF_FormField* pField = m_pFieldTree->m_Root.GetFieldAtIndex(i); + CPDF_FormField* pField = pRoot->GetFieldAtIndex(i); if (!pField || pField->GetType() == CPDF_FormField::kPushButton) continue; uint32_t dwFlags = pField->GetFieldFlags(); - if (dwFlags & 0x04) + if (dwFlags & pdfium::form_flags::kNoExport) continue; - if (bIncludeOrExclude != pdfium::ContainsValue(fields, pField)) + if (bIncludeOrExclude != pdfium::Contains(fields, pField)) continue; - if ((dwFlags & 0x02) != 0 && - pField->GetDict()->GetStringFor(pdfium::form_fields::kV).IsEmpty()) { + if ((dwFlags & pdfium::form_flags::kRequired) != 0 && + pField->GetFieldDict() + ->GetByteStringFor(pdfium::form_fields::kV) + .IsEmpty()) { continue; } WideString fullname = CPDF_FormField::GetFullNameForDict(pField->GetFieldDict()); auto pFieldDict = pDoc->New<CPDF_Dictionary>(); - pFieldDict->SetNewFor<CPDF_String>(pdfium::form_fields::kT, fullname); + pFieldDict->SetNewFor<CPDF_String>(pdfium::form_fields::kT, + fullname.AsStringView()); if (pField->GetType() == CPDF_FormField::kCheckBox || pField->GetType() == CPDF_FormField::kRadioButton) { WideString csExport = pField->GetCheckValue(false); - ByteString csBExport = PDF_EncodeText(csExport); - CPDF_Object* pOpt = - CPDF_FormField::GetFieldAttr(pField->GetDict(), "Opt"); + ByteString csBExport = PDF_EncodeText(csExport.AsStringView()); + RetainPtr<const CPDF_Object> pOpt = pField->GetFieldAttr("Opt"); if (pOpt) { pFieldDict->SetNewFor<CPDF_String>(pdfium::form_fields::kV, csBExport, false); @@ -1080,12 +988,12 @@ pFieldDict->SetNewFor<CPDF_Name>(pdfium::form_fields::kV, csBExport); } } else { - CPDF_Object* pV = CPDF_FormField::GetFieldAttr(pField->GetDict(), - pdfium::form_fields::kV); + RetainPtr<const CPDF_Object> pV = + pField->GetFieldAttr(pdfium::form_fields::kV); if (pV) pFieldDict->SetFor(pdfium::form_fields::kV, pV->CloneDirectObject()); } - pFields->Add(pFieldDict); + pFields->Append(pFieldDict); } return pDoc; } @@ -1093,3 +1001,31 @@ void CPDF_InteractiveForm::SetNotifierIface(NotifierIface* pNotify) { m_pFormNotify = pNotify; } + +bool CPDF_InteractiveForm::NotifyBeforeValueChange(CPDF_FormField* pField, + const WideString& csValue) { + return !m_pFormNotify || m_pFormNotify->BeforeValueChange(pField, csValue); +} + +void CPDF_InteractiveForm::NotifyAfterValueChange(CPDF_FormField* pField) { + if (m_pFormNotify) + m_pFormNotify->AfterValueChange(pField); +} + +bool CPDF_InteractiveForm::NotifyBeforeSelectionChange( + CPDF_FormField* pField, + const WideString& csValue) { + return !m_pFormNotify || + m_pFormNotify->BeforeSelectionChange(pField, csValue); +} + +void CPDF_InteractiveForm::NotifyAfterSelectionChange(CPDF_FormField* pField) { + if (m_pFormNotify) + m_pFormNotify->AfterSelectionChange(pField); +} + +void CPDF_InteractiveForm::NotifyAfterCheckedStatusChange( + CPDF_FormField* pField) { + if (m_pFormNotify) + m_pFormNotify->AfterCheckedStatusChange(pField); +}
diff --git a/core/fpdfdoc/cpdf_interactiveform.h b/core/fpdfdoc/cpdf_interactiveform.h index 7d1f6c2..3eb3c30 100644 --- a/core/fpdfdoc/cpdf_interactiveform.h +++ b/core/fpdfdoc/cpdf_interactiveform.h
@@ -1,4 +1,4 @@ -// Copyright 2016 PDFium Authors. All rights reserved. +// Copyright 2016 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -7,31 +7,31 @@ #ifndef CORE_FPDFDOC_CPDF_INTERACTIVEFORM_H_ #define CORE_FPDFDOC_CPDF_INTERACTIVEFORM_H_ +#include <stddef.h> +#include <stdint.h> + +#include <functional> #include <map> #include <memory> #include <vector> +#include "core/fpdfapi/parser/cpdf_dictionary.h" #include "core/fpdfapi/parser/fpdf_parser_decode.h" #include "core/fpdfdoc/cpdf_defaultappearance.h" #include "core/fpdfdoc/cpdf_formfield.h" +#include "core/fxcrt/fx_coordinates.h" #include "core/fxcrt/fx_string.h" -#include "core/fxcrt/fx_system.h" #include "core/fxcrt/retain_ptr.h" #include "core/fxcrt/unowned_ptr.h" +#include "third_party/base/span.h" class CFieldTree; class CFDF_Document; class CPDF_Document; -class CPDF_Dictionary; class CPDF_Font; class CPDF_FormControl; -class CPDF_Object; class CPDF_Page; -RetainPtr<CPDF_Font> AddNativeInteractiveFormFont(CPDF_Dictionary*& pFormDict, - CPDF_Document* pDocument, - ByteString* csNameTag); - class CPDF_InteractiveForm { public: class NotifierIface { @@ -51,23 +51,19 @@ explicit CPDF_InteractiveForm(CPDF_Document* pDocument); ~CPDF_InteractiveForm(); - static void SetUpdateAP(bool bUpdateAP); static bool IsUpdateAPEnabled(); - static uint8_t GetNativeCharSet(); - static ByteString GetNativeFontName(uint8_t iCharSet, void* pLogFont); - static RetainPtr<CPDF_Font> AddStandardFont(CPDF_Document* pDocument, - ByteString csFontName); - static RetainPtr<CPDF_Font> AddNativeFont(uint8_t iCharSet, - CPDF_Document* pDocument); - static RetainPtr<CPDF_Font> AddNativeFont(CPDF_Document* pDocument); + static void SetUpdateAP(bool bUpdateAP); + static RetainPtr<CPDF_Font> AddNativeInteractiveFormFont( + CPDF_Document* pDocument, + ByteString* csNameTag); size_t CountFields(const WideString& csFieldName) const; - CPDF_FormField* GetField(uint32_t index, const WideString& csFieldName) const; - CPDF_FormField* GetFieldByDict(CPDF_Dictionary* pFieldDict) const; + CPDF_FormField* GetField(size_t index, const WideString& csFieldName) const; + CPDF_FormField* GetFieldByDict(const CPDF_Dictionary* pFieldDict) const; - CPDF_FormControl* GetControlAtPoint(CPDF_Page* pPage, - const CFX_PointF& point, - int* z_order) const; + const CPDF_FormControl* GetControlAtPoint(const CPDF_Page* pPage, + const CFX_PointF& point, + int* z_order) const; CPDF_FormControl* GetControlByDict(const CPDF_Dictionary* pWidgetDict) const; bool NeedConstructAP() const; @@ -76,44 +72,42 @@ int FindFieldInCalculationOrder(const CPDF_FormField* pField); RetainPtr<CPDF_Font> GetFormFont(ByteString csNameTag) const; + RetainPtr<CPDF_Font> GetFontForElement( + RetainPtr<CPDF_Dictionary> pElement) const; CPDF_DefaultAppearance GetDefaultAppearance() const; int GetFormAlignment() const; - bool CheckRequiredFields(const std::vector<CPDF_FormField*>* fields, bool bIncludeOrExclude) const; - std::unique_ptr<CFDF_Document> ExportToFDF(const WideString& pdf_path, - bool bSimpleFileSpec) const; - + std::unique_ptr<CFDF_Document> ExportToFDF(const WideString& pdf_path) const; std::unique_ptr<CFDF_Document> ExportToFDF( const WideString& pdf_path, const std::vector<CPDF_FormField*>& fields, - bool bIncludeOrExclude, - bool bSimpleFileSpec) const; + bool bIncludeOrExclude) const; - void ResetForm(NotificationOption notify); - - // TODO(tsepez): Use a span. - void ResetForm(const std::vector<CPDF_FormField*>& fields, - bool bIncludeOrExclude, - NotificationOption notify); + void ResetForm(); + void ResetForm(pdfium::span<CPDF_FormField*> fields, bool bIncludeOrExclude); void SetNotifierIface(NotifierIface* pNotify); - bool HasXFAForm() const; void FixPageFields(CPDF_Page* pPage); - NotifierIface* GetFormNotify() const { return m_pFormNotify.Get(); } - CPDF_Document* GetDocument() const { return m_pDocument.Get(); } - CPDF_Dictionary* GetFormDict() const { return m_pFormDict.Get(); } + // Wrap callbacks thru NotifierIface. + bool NotifyBeforeValueChange(CPDF_FormField* pField, + const WideString& csValue); + void NotifyAfterValueChange(CPDF_FormField* pField); + bool NotifyBeforeSelectionChange(CPDF_FormField* pField, + const WideString& csValue); + void NotifyAfterSelectionChange(CPDF_FormField* pField); + void NotifyAfterCheckedStatusChange(CPDF_FormField* pField); const std::vector<UnownedPtr<CPDF_FormControl>>& GetControlsForField( const CPDF_FormField* pField); private: - void LoadField(CPDF_Dictionary* pFieldDict, int nLevel); - void AddTerminalField(CPDF_Dictionary* pFieldDict); + void LoadField(RetainPtr<CPDF_Dictionary> pFieldDict, int nLevel); + void AddTerminalField(RetainPtr<CPDF_Dictionary> pFieldDict); CPDF_FormControl* AddControl(CPDF_FormField* pField, - CPDF_Dictionary* pWidgetDict); + RetainPtr<CPDF_Dictionary> pWidgetDict); static bool s_bUpdateAP; @@ -121,10 +115,14 @@ UnownedPtr<CPDF_Document> const m_pDocument; RetainPtr<CPDF_Dictionary> m_pFormDict; std::unique_ptr<CFieldTree> m_pFieldTree; - std::map<const CPDF_Dictionary*, std::unique_ptr<CPDF_FormControl>> + std::map<RetainPtr<const CPDF_Dictionary>, + std::unique_ptr<CPDF_FormControl>, + std::less<>> m_ControlMap; // Points into |m_ControlMap|. - std::map<const CPDF_FormField*, std::vector<UnownedPtr<CPDF_FormControl>>> + std::map<UnownedPtr<const CPDF_FormField>, + std::vector<UnownedPtr<CPDF_FormControl>>, + std::less<>> m_ControlLists; UnownedPtr<NotifierIface> m_pFormNotify; };
diff --git a/core/fpdfdoc/cpdf_link.cpp b/core/fpdfdoc/cpdf_link.cpp index d5f24b1..d68585e 100644 --- a/core/fpdfdoc/cpdf_link.cpp +++ b/core/fpdfdoc/cpdf_link.cpp
@@ -1,4 +1,4 @@ -// Copyright 2016 PDFium Authors. All rights reserved. +// Copyright 2016 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -6,13 +6,14 @@ #include "core/fpdfdoc/cpdf_link.h" -#include "core/fpdfapi/parser/cpdf_array.h" +#include <utility> + #include "core/fpdfapi/parser/cpdf_dictionary.h" -#include "core/fpdfdoc/cpdf_nametree.h" CPDF_Link::CPDF_Link() = default; -CPDF_Link::CPDF_Link(CPDF_Dictionary* pDict) : m_pDict(pDict) {} +CPDF_Link::CPDF_Link(RetainPtr<CPDF_Dictionary> pDict) + : m_pDict(std::move(pDict)) {} CPDF_Link::CPDF_Link(const CPDF_Link& that) = default; @@ -23,17 +24,7 @@ } CPDF_Dest CPDF_Link::GetDest(CPDF_Document* pDoc) { - CPDF_Object* pDest = m_pDict->GetDirectObjectFor("Dest"); - if (!pDest) - return CPDF_Dest(); - - if (pDest->IsString() || pDest->IsName()) { - CPDF_NameTree name_tree(pDoc, "Dests"); - return CPDF_Dest(name_tree.LookupNamedDest(pDoc, pDest->GetUnicodeText())); - } - if (CPDF_Array* pArray = pDest->AsArray()) - return CPDF_Dest(pArray); - return CPDF_Dest(); + return CPDF_Dest::Create(pDoc, m_pDict->GetDirectObjectFor("Dest")); } CPDF_Action CPDF_Link::GetAction() {
diff --git a/core/fpdfdoc/cpdf_link.h b/core/fpdfdoc/cpdf_link.h index aaa6e8e..2432fd6 100644 --- a/core/fpdfdoc/cpdf_link.h +++ b/core/fpdfdoc/cpdf_link.h
@@ -1,4 +1,4 @@ -// Copyright 2016 PDFium Authors. All rights reserved. +// Copyright 2016 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -7,21 +7,20 @@ #ifndef CORE_FPDFDOC_CPDF_LINK_H_ #define CORE_FPDFDOC_CPDF_LINK_H_ +#include "core/fpdfapi/parser/cpdf_dictionary.h" #include "core/fpdfdoc/cpdf_action.h" #include "core/fpdfdoc/cpdf_dest.h" #include "core/fxcrt/fx_coordinates.h" #include "core/fxcrt/retain_ptr.h" -class CPDF_Dictionary; - class CPDF_Link { public: CPDF_Link(); - explicit CPDF_Link(CPDF_Dictionary* pDict); + explicit CPDF_Link(RetainPtr<CPDF_Dictionary> pDict); CPDF_Link(const CPDF_Link& that); ~CPDF_Link(); - CPDF_Dictionary* GetDict() const { return m_pDict.Get(); } + RetainPtr<CPDF_Dictionary> GetMutableDict() const { return m_pDict; } CFX_FloatRect GetRect(); CPDF_Dest GetDest(CPDF_Document* pDoc); CPDF_Action GetAction();
diff --git a/core/fpdfdoc/cpdf_linklist.cpp b/core/fpdfdoc/cpdf_linklist.cpp index 746bbab..cd4e202 100644 --- a/core/fpdfdoc/cpdf_linklist.cpp +++ b/core/fpdfdoc/cpdf_linklist.cpp
@@ -1,4 +1,4 @@ -// Copyright 2016 PDFium Authors. All rights reserved. +// Copyright 2016 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -6,15 +6,43 @@ #include "core/fpdfdoc/cpdf_linklist.h" +#include <utility> + #include "core/fpdfapi/page/cpdf_page.h" #include "core/fpdfapi/parser/cpdf_array.h" #include "core/fpdfapi/parser/cpdf_dictionary.h" +#include "third_party/base/numerics/safe_conversions.h" CPDF_LinkList::CPDF_LinkList() = default; CPDF_LinkList::~CPDF_LinkList() = default; -const std::vector<CPDF_Dictionary*>* CPDF_LinkList::GetPageLinks( +CPDF_Link CPDF_LinkList::GetLinkAtPoint(CPDF_Page* pPage, + const CFX_PointF& point, + int* z_order) { + const std::vector<RetainPtr<CPDF_Dictionary>>* pPageLinkList = + GetPageLinks(pPage); + if (!pPageLinkList) + return CPDF_Link(); + + for (size_t i = pPageLinkList->size(); i > 0; --i) { + size_t annot_index = i - 1; + RetainPtr<CPDF_Dictionary> pAnnot = (*pPageLinkList)[annot_index]; + if (!pAnnot) + continue; + + CPDF_Link link(std::move(pAnnot)); + if (!link.GetRect().Contains(point)) + continue; + + if (z_order) + *z_order = pdfium::base::checked_cast<int32_t>(annot_index); + return link; + } + return CPDF_Link(); +} + +const std::vector<RetainPtr<CPDF_Dictionary>>* CPDF_LinkList::GetPageLinks( CPDF_Page* pPage) { uint32_t objnum = pPage->GetDict()->GetObjNum(); if (objnum == 0) @@ -25,45 +53,16 @@ return &it->second; // std::map::operator[] forces the creation of a map entry. - std::vector<CPDF_Dictionary*>& page_link_list = m_PageMap[objnum]; - LoadPageLinks(pPage, &page_link_list); - return &page_link_list; -} - -CPDF_Link CPDF_LinkList::GetLinkAtPoint(CPDF_Page* pPage, - const CFX_PointF& point, - int* z_order) { - const std::vector<CPDF_Dictionary*>* pPageLinkList = GetPageLinks(pPage); - if (!pPageLinkList) - return CPDF_Link(); - - for (size_t i = pPageLinkList->size(); i > 0; --i) { - size_t annot_index = i - 1; - CPDF_Dictionary* pAnnot = (*pPageLinkList)[annot_index]; - if (!pAnnot) - continue; - - CPDF_Link link(pAnnot); - if (!link.GetRect().Contains(point)) - continue; - - if (z_order) - *z_order = annot_index; - return link; - } - return CPDF_Link(); -} - -void CPDF_LinkList::LoadPageLinks(CPDF_Page* pPage, - std::vector<CPDF_Dictionary*>* pList) { - CPDF_Array* pAnnotList = pPage->GetDict()->GetArrayFor("Annots"); + auto* page_link_list = &m_PageMap[objnum]; + RetainPtr<CPDF_Array> pAnnotList = pPage->GetMutableAnnotsArray(); if (!pAnnotList) - return; + return page_link_list; for (size_t i = 0; i < pAnnotList->size(); ++i) { - CPDF_Dictionary* pAnnot = pAnnotList->GetDictAt(i); - bool add_link = (pAnnot && pAnnot->GetStringFor("Subtype") == "Link"); + RetainPtr<CPDF_Dictionary> pAnnot = pAnnotList->GetMutableDictAt(i); + bool add_link = (pAnnot && pAnnot->GetByteStringFor("Subtype") == "Link"); // Add non-links as nullptrs to preserve z-order. - pList->push_back(add_link ? pAnnot : nullptr); + page_link_list->emplace_back(add_link ? pAnnot : nullptr); } + return page_link_list; }
diff --git a/core/fpdfdoc/cpdf_linklist.h b/core/fpdfdoc/cpdf_linklist.h index 442f66c..d264718 100644 --- a/core/fpdfdoc/cpdf_linklist.h +++ b/core/fpdfdoc/cpdf_linklist.h
@@ -1,4 +1,4 @@ -// Copyright 2016 PDFium Authors. All rights reserved. +// Copyright 2016 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -7,17 +7,19 @@ #ifndef CORE_FPDFDOC_CPDF_LINKLIST_H_ #define CORE_FPDFDOC_CPDF_LINKLIST_H_ +#include <stdint.h> + #include <map> #include <vector> #include "core/fpdfapi/parser/cpdf_document.h" #include "core/fpdfdoc/cpdf_link.h" -#include "core/fxcrt/fx_system.h" +#include "core/fxcrt/retain_ptr.h" class CPDF_Page; class CPDF_Dictionary; -class CPDF_LinkList : public CPDF_Document::LinkListIface { +class CPDF_LinkList final : public CPDF_Document::LinkListIface { public: CPDF_LinkList(); ~CPDF_LinkList() override; @@ -27,10 +29,9 @@ int* z_order); private: - const std::vector<CPDF_Dictionary*>* GetPageLinks(CPDF_Page* pPage); - void LoadPageLinks(CPDF_Page* pPage, std::vector<CPDF_Dictionary*>* pList); + const std::vector<RetainPtr<CPDF_Dictionary>>* GetPageLinks(CPDF_Page* pPage); - std::map<uint32_t, std::vector<CPDF_Dictionary*>> m_PageMap; + std::map<uint32_t, std::vector<RetainPtr<CPDF_Dictionary>>> m_PageMap; }; #endif // CORE_FPDFDOC_CPDF_LINKLIST_H_
diff --git a/core/fpdfdoc/cpdf_metadata.cpp b/core/fpdfdoc/cpdf_metadata.cpp index da8dcb9..228a0c1 100644 --- a/core/fpdfdoc/cpdf_metadata.cpp +++ b/core/fpdfdoc/cpdf_metadata.cpp
@@ -1,4 +1,4 @@ -// Copyright 2016 PDFium Authors. All rights reserved. +// Copyright 2016 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -7,14 +7,16 @@ #include "core/fpdfdoc/cpdf_metadata.h" #include <memory> +#include <utility> #include "core/fpdfapi/parser/cpdf_stream.h" #include "core/fpdfapi/parser/cpdf_stream_acc.h" -#include "core/fxcrt/cfx_readonlymemorystream.h" +#include "core/fxcrt/cfx_read_only_span_stream.h" #include "core/fxcrt/fx_codepage.h" #include "core/fxcrt/xml/cfx_xmldocument.h" #include "core/fxcrt/xml/cfx_xmlelement.h" #include "core/fxcrt/xml/cfx_xmlparser.h" +#include "third_party/base/check.h" namespace { @@ -60,17 +62,18 @@ } // namespace -CPDF_Metadata::CPDF_Metadata(const CPDF_Stream* pStream) : stream_(pStream) { - ASSERT(pStream); +CPDF_Metadata::CPDF_Metadata(RetainPtr<const CPDF_Stream> pStream) + : stream_(std::move(pStream)) { + DCHECK(stream_); } CPDF_Metadata::~CPDF_Metadata() = default; std::vector<UnsupportedFeature> CPDF_Metadata::CheckForSharedForm() const { - auto pAcc = pdfium::MakeRetain<CPDF_StreamAcc>(stream_.Get()); + auto pAcc = pdfium::MakeRetain<CPDF_StreamAcc>(stream_); pAcc->LoadAllDataFiltered(); - auto stream = pdfium::MakeRetain<CFX_ReadOnlyMemoryStream>(pAcc->GetSpan()); + auto stream = pdfium::MakeRetain<CFX_ReadOnlySpanStream>(pAcc->GetSpan()); CFX_XMLParser parser(stream); std::unique_ptr<CFX_XMLDocument> doc = parser.Parse(); if (!doc)
diff --git a/core/fpdfdoc/cpdf_metadata.h b/core/fpdfdoc/cpdf_metadata.h index 554492a..6b63e22 100644 --- a/core/fpdfdoc/cpdf_metadata.h +++ b/core/fpdfdoc/cpdf_metadata.h
@@ -1,4 +1,4 @@ -// Copyright 2016 PDFium Authors. All rights reserved. +// Copyright 2016 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -34,7 +34,7 @@ class CPDF_Metadata { public: - explicit CPDF_Metadata(const CPDF_Stream* pStream); + explicit CPDF_Metadata(RetainPtr<const CPDF_Stream> pStream); ~CPDF_Metadata(); std::vector<UnsupportedFeature> CheckForSharedForm() const;
diff --git a/core/fpdfdoc/cpdf_metadata_unittest.cpp b/core/fpdfdoc/cpdf_metadata_unittest.cpp index 41f4b5d..cfcb8f3 100644 --- a/core/fpdfdoc/cpdf_metadata_unittest.cpp +++ b/core/fpdfdoc/cpdf_metadata_unittest.cpp
@@ -1,4 +1,4 @@ -// Copyright 2018 PDFium Authors. All rights reserved. +// Copyright 2018 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -17,7 +17,7 @@ auto stream = pdfium::MakeRetain<CPDF_Stream>(); stream->SetData(ByteStringView(data).raw_span()); - CPDF_Metadata metadata(stream.Get()); + CPDF_Metadata metadata(stream); auto results = metadata.CheckForSharedForm(); ASSERT_EQ(1U, results.size()); @@ -34,7 +34,7 @@ auto stream = pdfium::MakeRetain<CPDF_Stream>(); stream->SetData(ByteStringView(data).raw_span()); - CPDF_Metadata metadata(stream.Get()); + CPDF_Metadata metadata(stream); auto results = metadata.CheckForSharedForm(); ASSERT_EQ(1U, results.size()); @@ -51,7 +51,7 @@ auto stream = pdfium::MakeRetain<CPDF_Stream>(); stream->SetData(ByteStringView(data).raw_span()); - CPDF_Metadata metadata(stream.Get()); + CPDF_Metadata metadata(stream); auto results = metadata.CheckForSharedForm(); ASSERT_EQ(1U, results.size()); @@ -68,7 +68,7 @@ auto stream = pdfium::MakeRetain<CPDF_Stream>(); stream->SetData(ByteStringView(data).raw_span()); - CPDF_Metadata metadata(stream.Get()); + CPDF_Metadata metadata(stream); auto results = metadata.CheckForSharedForm(); EXPECT_EQ(0U, results.size()); @@ -86,7 +86,7 @@ auto stream = pdfium::MakeRetain<CPDF_Stream>(); stream->SetData(ByteStringView(data).raw_span()); - CPDF_Metadata metadata(stream.Get()); + CPDF_Metadata metadata(stream); auto results = metadata.CheckForSharedForm(); ASSERT_EQ(1U, results.size()); @@ -100,7 +100,7 @@ auto stream = pdfium::MakeRetain<CPDF_Stream>(); stream->SetData(ByteStringView(data).raw_span()); - CPDF_Metadata metadata(stream.Get()); + CPDF_Metadata metadata(stream); auto results = metadata.CheckForSharedForm(); EXPECT_EQ(0U, results.size()); @@ -116,7 +116,7 @@ auto stream = pdfium::MakeRetain<CPDF_Stream>(); stream->SetData(ByteStringView(data).raw_span()); - CPDF_Metadata metadata(stream.Get()); + CPDF_Metadata metadata(stream); auto results = metadata.CheckForSharedForm(); EXPECT_EQ(0U, results.size()); @@ -146,7 +146,7 @@ auto stream = pdfium::MakeRetain<CPDF_Stream>(); stream->SetData(ByteStringView(data).raw_span()); - CPDF_Metadata metadata(stream.Get()); + CPDF_Metadata metadata(stream); auto results = metadata.CheckForSharedForm(); ASSERT_EQ(3U, results.size());
diff --git a/core/fpdfdoc/cpdf_nametree.cpp b/core/fpdfdoc/cpdf_nametree.cpp index b232540..3b60fab 100644 --- a/core/fpdfdoc/cpdf_nametree.cpp +++ b/core/fpdfdoc/cpdf_nametree.cpp
@@ -1,4 +1,4 @@ -// Copyright 2016 PDFium Authors. All rights reserved. +// Copyright 2016 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -6,65 +6,83 @@ #include "core/fpdfdoc/cpdf_nametree.h" +#include <set> #include <utility> #include <vector> #include "core/fpdfapi/parser/cpdf_array.h" #include "core/fpdfapi/parser/cpdf_dictionary.h" #include "core/fpdfapi/parser/cpdf_document.h" +#include "core/fpdfapi/parser/cpdf_reference.h" #include "core/fpdfapi/parser/cpdf_string.h" #include "core/fpdfapi/parser/fpdf_parser_decode.h" +#include "core/fxcrt/stl_util.h" +#include "third_party/base/check.h" +#include "third_party/base/ptr_util.h" namespace { constexpr int kNameTreeMaxRecursion = 32; -std::pair<WideString, WideString> GetNodeLimitsMaybeSwap(CPDF_Array* pLimits) { - ASSERT(pLimits); +std::pair<WideString, WideString> GetNodeLimitsAndSanitize( + CPDF_Array* pLimits) { + DCHECK(pLimits); WideString csLeft = pLimits->GetUnicodeTextAt(0); WideString csRight = pLimits->GetUnicodeTextAt(1); // If the lower limit is greater than the upper limit, swap them. if (csLeft.Compare(csRight) > 0) { - pLimits->SetNewAt<CPDF_String>(0, csRight); - pLimits->SetNewAt<CPDF_String>(1, csLeft); + pLimits->SetNewAt<CPDF_String>(0, csRight.AsStringView()); + pLimits->SetNewAt<CPDF_String>(1, csLeft.AsStringView()); csLeft = pLimits->GetUnicodeTextAt(0); csRight = pLimits->GetUnicodeTextAt(1); } + while (pLimits->size() > 2) + pLimits->RemoveAt(pLimits->size() - 1); return {csLeft, csRight}; } // Get the limit arrays that leaf array |pFind| is under in the tree with root // |pNode|. |pLimits| will hold all the limit arrays from the leaf up to before // the root. Return true if successful. -bool GetNodeAncestorsLimits(CPDF_Dictionary* pNode, - const CPDF_Array* pFind, - int nLevel, - std::vector<CPDF_Array*>* pLimits) { +bool GetNodeAncestorsLimitsInternal(const RetainPtr<CPDF_Dictionary>& pNode, + const CPDF_Array* pFind, + int nLevel, + std::vector<CPDF_Array*>* pLimits) { if (nLevel > kNameTreeMaxRecursion) return false; if (pNode->GetArrayFor("Names") == pFind) { - pLimits->push_back(pNode->GetArrayFor("Limits")); + pLimits->push_back(pNode->GetMutableArrayFor("Limits").Get()); return true; } - CPDF_Array* pKids = pNode->GetArrayFor("Kids"); + RetainPtr<CPDF_Array> pKids = pNode->GetMutableArrayFor("Kids"); if (!pKids) return false; for (size_t i = 0; i < pKids->size(); ++i) { - CPDF_Dictionary* pKid = pKids->GetDictAt(i); + RetainPtr<CPDF_Dictionary> pKid = pKids->GetMutableDictAt(i); if (!pKid) continue; - if (GetNodeAncestorsLimits(pKid, pFind, nLevel + 1, pLimits)) { - pLimits->push_back(pNode->GetArrayFor("Limits")); + if (GetNodeAncestorsLimitsInternal(pKid, pFind, nLevel + 1, pLimits)) { + pLimits->push_back(pNode->GetMutableArrayFor("Limits").Get()); return true; } } return false; } +// Wrapper for GetNodeAncestorsLimitsInternal() so callers do not need to know +// about the details. +std::vector<CPDF_Array*> GetNodeAncestorsLimits( + const RetainPtr<CPDF_Dictionary>& pNode, + const CPDF_Array* pFind) { + std::vector<CPDF_Array*> results; + GetNodeAncestorsLimitsInternal(pNode, pFind, 0, &results); + return results; +} + // Upon the deletion of |csName| from leaf array |pFind|, update the ancestors // of |pFind|. Specifically, the limits of |pFind|'s ancestors will be updated // if needed, and any ancestors that are now empty will be removed. @@ -75,13 +93,13 @@ if (nLevel > kNameTreeMaxRecursion) return false; - CPDF_Array* pLimits = pNode->GetArrayFor("Limits"); + RetainPtr<CPDF_Array> pLimits = pNode->GetMutableArrayFor("Limits"); WideString csLeft; WideString csRight; if (pLimits) - std::tie(csLeft, csRight) = GetNodeLimitsMaybeSwap(pLimits); + std::tie(csLeft, csRight) = GetNodeLimitsAndSanitize(pLimits.Get()); - CPDF_Array* pNames = pNode->GetArrayFor("Names"); + RetainPtr<const CPDF_Array> pNames = pNode->GetArrayFor("Names"); if (pNames) { if (pNames != pFind) return false; @@ -101,23 +119,24 @@ if (wsName.Compare(csNewRight) > 0) csNewRight = wsName; } - pLimits->SetNewAt<CPDF_String>(0, csNewLeft); - pLimits->SetNewAt<CPDF_String>(1, csNewRight); + pLimits->SetNewAt<CPDF_String>(0, csNewLeft.AsStringView()); + pLimits->SetNewAt<CPDF_String>(1, csNewRight.AsStringView()); return true; } - CPDF_Array* pKids = pNode->GetArrayFor("Kids"); + RetainPtr<CPDF_Array> pKids = pNode->GetMutableArrayFor("Kids"); if (!pKids) return false; // Loop through the kids to find the leaf array |pFind|. for (size_t i = 0; i < pKids->size(); ++i) { - CPDF_Dictionary* pKid = pKids->GetDictAt(i); + RetainPtr<CPDF_Dictionary> pKid = pKids->GetMutableDictAt(i); if (!pKid) continue; - if (!UpdateNodesAndLimitsUponDeletion(pKid, pFind, csName, nLevel + 1)) + if (!UpdateNodesAndLimitsUponDeletion(pKid.Get(), pFind, csName, + nLevel + 1)) { continue; - + } // Remove this child node if it's empty. if ((pKid->KeyExist("Names") && pKid->GetArrayFor("Names")->IsEmpty()) || (pKid->KeyExist("Kids") && pKid->GetArrayFor("Kids")->IsEmpty())) { @@ -133,41 +152,72 @@ WideString csNewLeft = csRight; WideString csNewRight = csLeft; for (size_t j = 0; j < pKids->size(); ++j) { - CPDF_Array* pKidLimits = pKids->GetDictAt(j)->GetArrayFor("Limits"); - ASSERT(pKidLimits); + RetainPtr<const CPDF_Array> pKidLimits = + pKids->GetDictAt(j)->GetArrayFor("Limits"); + DCHECK(pKidLimits); if (pKidLimits->GetUnicodeTextAt(0).Compare(csNewLeft) < 0) csNewLeft = pKidLimits->GetUnicodeTextAt(0); if (pKidLimits->GetUnicodeTextAt(1).Compare(csNewRight) > 0) csNewRight = pKidLimits->GetUnicodeTextAt(1); } - pLimits->SetNewAt<CPDF_String>(0, csNewLeft); - pLimits->SetNewAt<CPDF_String>(1, csNewRight); + pLimits->SetNewAt<CPDF_String>(0, csNewLeft.AsStringView()); + pLimits->SetNewAt<CPDF_String>(1, csNewRight.AsStringView()); return true; } return false; } +bool IsTraversedObject(const CPDF_Object* obj, + std::set<uint32_t>* seen_obj_nums) { + uint32_t obj_num = obj->GetObjNum(); + if (!obj_num) + return false; + + bool inserted = seen_obj_nums->insert(obj_num).second; + return !inserted; +} + +bool IsArrayWithTraversedObject(const CPDF_Array* array, + std::set<uint32_t>* seen_obj_nums) { + if (IsTraversedObject(array, seen_obj_nums)) + return true; + + CPDF_ArrayLocker locker(array); + for (const auto& item : locker) { + if (IsTraversedObject(item.Get(), seen_obj_nums)) + return true; + } + return false; +} + // Search for |csName| in the tree with root |pNode|. If successful, return the // value that |csName| points to; |nIndex| will be the index of |csName|, // |ppFind| will be the leaf array that |csName| is found in, and |pFindIndex| // will be the index of |csName| in |ppFind|. If |csName| is not found, |ppFind| // will be the leaf array that |csName| should be added to, and |pFindIndex| // will be the index that it should be added at. -CPDF_Object* SearchNameNodeByName(CPDF_Dictionary* pNode, - const WideString& csName, - int nLevel, - size_t* nIndex, - CPDF_Array** ppFind, - int* pFindIndex) { +RetainPtr<const CPDF_Object> SearchNameNodeByNameInternal( + const RetainPtr<CPDF_Dictionary>& pNode, + const WideString& csName, + int nLevel, + size_t* nIndex, + RetainPtr<CPDF_Array>* ppFind, + int* pFindIndex, + std::set<uint32_t>* seen_obj_nums) { if (nLevel > kNameTreeMaxRecursion) return nullptr; - CPDF_Array* pLimits = pNode->GetArrayFor("Limits"); - CPDF_Array* pNames = pNode->GetArrayFor("Names"); + RetainPtr<CPDF_Array> pLimits = pNode->GetMutableArrayFor("Limits"); + RetainPtr<CPDF_Array> pNames = pNode->GetMutableArrayFor("Names"); + if (pNames && IsArrayWithTraversedObject(pNames.Get(), seen_obj_nums)) + pNames.Reset(); + if (pLimits && IsArrayWithTraversedObject(pLimits.Get(), seen_obj_nums)) + pLimits.Reset(); + if (pLimits) { WideString csLeft; WideString csRight; - std::tie(csLeft, csRight) = GetNodeLimitsMaybeSwap(pLimits); + std::tie(csLeft, csRight) = GetNodeLimitsAndSanitize(pLimits.Get()); // Skip this node if the name to look for is smaller than its lower limit. if (csName.Compare(csLeft) < 0) return nullptr; @@ -178,8 +228,7 @@ if (ppFind) *ppFind = pNames; if (pFindIndex) - *pFindIndex = pNames->size() / 2 - 1; - + *pFindIndex = fxcrt::CollectionSize<int32_t>(*pNames) / 2 - 1; return nullptr; } } @@ -195,7 +244,7 @@ if (ppFind) *ppFind = pNames; if (pFindIndex) - *pFindIndex = i; + *pFindIndex = pdfium::base::checked_cast<int32_t>(i); if (iCompare < 0) continue; @@ -207,127 +256,248 @@ } // Search through the node's children. - CPDF_Array* pKids = pNode->GetArrayFor("Kids"); - if (!pKids) + RetainPtr<CPDF_Array> pKids = pNode->GetMutableArrayFor("Kids"); + if (!pKids || IsTraversedObject(pKids.Get(), seen_obj_nums)) return nullptr; for (size_t i = 0; i < pKids->size(); i++) { - CPDF_Dictionary* pKid = pKids->GetDictAt(i); - if (!pKid) + RetainPtr<CPDF_Dictionary> pKid = pKids->GetMutableDictAt(i); + if (!pKid || IsTraversedObject(pKid.Get(), seen_obj_nums)) continue; - CPDF_Object* pFound = SearchNameNodeByName(pKid, csName, nLevel + 1, nIndex, - ppFind, pFindIndex); + RetainPtr<const CPDF_Object> pFound = SearchNameNodeByNameInternal( + pKid, csName, nLevel + 1, nIndex, ppFind, pFindIndex, seen_obj_nums); if (pFound) return pFound; } return nullptr; } -// Get the key-value pair at |nIndex| in the tree with root |pNode|. If -// successful, return the value object; |csName| will be the key, |ppFind| -// will be the leaf array that this pair is in, and |pFindIndex| will be the -// index of the pair in |pFind|. -CPDF_Object* SearchNameNodeByIndex(CPDF_Dictionary* pNode, - size_t nIndex, - int nLevel, - size_t* nCurIndex, - WideString* csName, - CPDF_Array** ppFind, - int* pFindIndex) { - if (nLevel > kNameTreeMaxRecursion) - return nullptr; +// Wrapper for SearchNameNodeByNameInternal() so callers do not need to know +// about the details. +RetainPtr<const CPDF_Object> SearchNameNodeByName( + const RetainPtr<CPDF_Dictionary>& pNode, + const WideString& csName, + RetainPtr<CPDF_Array>* ppFind, + int* pFindIndex) { + size_t nIndex = 0; + std::set<uint32_t> seen_obj_nums; + return SearchNameNodeByNameInternal(pNode, csName, 0, &nIndex, ppFind, + pFindIndex, &seen_obj_nums); +} - CPDF_Array* pNames = pNode->GetArrayFor("Names"); +struct IndexSearchResult { + // For the n-th object in a tree, the key and value. + WideString key; + RetainPtr<CPDF_Object> value; + // The leaf node that holds `key` and `value`. + RetainPtr<CPDF_Array> container; + // The index for `key` in `container`. Must be even. + size_t index; +}; + +// Find the `nTargetPairIndex` node in the tree with root `pNode`. `nLevel` +// tracks the recursion level and `nCurPairIndex` tracks the progress towards +// `nTargetPairIndex`. +absl::optional<IndexSearchResult> SearchNameNodeByIndexInternal( + CPDF_Dictionary* pNode, + size_t nTargetPairIndex, + int nLevel, + size_t* nCurPairIndex) { + if (nLevel > kNameTreeMaxRecursion) + return absl::nullopt; + + RetainPtr<CPDF_Array> pNames = pNode->GetMutableArrayFor("Names"); if (pNames) { size_t nCount = pNames->size() / 2; - if (nIndex >= *nCurIndex + nCount) { - *nCurIndex += nCount; - return nullptr; + if (nTargetPairIndex >= *nCurPairIndex + nCount) { + *nCurPairIndex += nCount; + return absl::nullopt; } - if (ppFind) - *ppFind = pNames; - if (pFindIndex) - *pFindIndex = nIndex - *nCurIndex; - *csName = pNames->GetUnicodeTextAt((nIndex - *nCurIndex) * 2); - return pNames->GetDirectObjectAt((nIndex - *nCurIndex) * 2 + 1); + size_t index = 2 * (nTargetPairIndex - *nCurPairIndex); + RetainPtr<CPDF_Object> value = pNames->GetMutableDirectObjectAt(index + 1); + if (!value) + return absl::nullopt; + + IndexSearchResult result; + result.key = pNames->GetUnicodeTextAt(index); + result.value = std::move(value); + result.container = std::move(pNames); + result.index = index; + return result; } - CPDF_Array* pKids = pNode->GetArrayFor("Kids"); + RetainPtr<CPDF_Array> pKids = pNode->GetMutableArrayFor("Kids"); if (!pKids) - return nullptr; + return absl::nullopt; for (size_t i = 0; i < pKids->size(); i++) { - CPDF_Dictionary* pKid = pKids->GetDictAt(i); + RetainPtr<CPDF_Dictionary> pKid = pKids->GetMutableDictAt(i); if (!pKid) continue; - CPDF_Object* pFound = SearchNameNodeByIndex( - pKid, nIndex, nLevel + 1, nCurIndex, csName, ppFind, pFindIndex); - if (pFound) - return pFound; + absl::optional<IndexSearchResult> result = SearchNameNodeByIndexInternal( + pKid.Get(), nTargetPairIndex, nLevel + 1, nCurPairIndex); + if (result.has_value()) + return result; } - return nullptr; + return absl::nullopt; +} + +// Wrapper for SearchNameNodeByIndexInternal() so callers do not need to know +// about the details. +absl::optional<IndexSearchResult> SearchNameNodeByIndex( + CPDF_Dictionary* pNode, + size_t nTargetPairIndex) { + size_t nCurPairIndex = 0; + return SearchNameNodeByIndexInternal(pNode, nTargetPairIndex, 0, + &nCurPairIndex); } // Get the total number of key-value pairs in the tree with root |pNode|. -size_t CountNamesInternal(CPDF_Dictionary* pNode, int nLevel) { +size_t CountNamesInternal(const CPDF_Dictionary* pNode, + int nLevel, + std::set<const CPDF_Dictionary*>& seen) { if (nLevel > kNameTreeMaxRecursion) return 0; - CPDF_Array* pNames = pNode->GetArrayFor("Names"); + const bool inserted = seen.insert(pNode).second; + if (!inserted) + return 0; + + RetainPtr<const CPDF_Array> pNames = pNode->GetArrayFor("Names"); if (pNames) return pNames->size() / 2; - CPDF_Array* pKids = pNode->GetArrayFor("Kids"); + RetainPtr<const CPDF_Array> pKids = pNode->GetArrayFor("Kids"); if (!pKids) return 0; size_t nCount = 0; for (size_t i = 0; i < pKids->size(); i++) { - CPDF_Dictionary* pKid = pKids->GetDictAt(i); + RetainPtr<const CPDF_Dictionary> pKid = pKids->GetDictAt(i); if (!pKid) continue; - nCount += CountNamesInternal(pKid, nLevel + 1); + nCount += CountNamesInternal(pKid.Get(), nLevel + 1, seen); } return nCount; } -} // namespace - -CPDF_NameTree::CPDF_NameTree(CPDF_Dictionary* pRoot) : m_pRoot(pRoot) {} - -CPDF_NameTree::CPDF_NameTree(CPDF_Document* pDoc, const ByteString& category) { - CPDF_Dictionary* pRoot = pDoc->GetRoot(); - if (!pRoot) - return; - - CPDF_Dictionary* pNames = pRoot->GetDictFor("Names"); - if (!pNames) - return; - - m_pRoot.Reset(pNames->GetDictFor(category)); +RetainPtr<const CPDF_Array> GetNamedDestFromObject( + RetainPtr<const CPDF_Object> obj) { + RetainPtr<const CPDF_Array> array = ToArray(obj); + if (array) + return array; + RetainPtr<const CPDF_Dictionary> dict = ToDictionary(obj); + if (dict) + return dict->GetArrayFor("D"); + return nullptr; } -CPDF_NameTree::~CPDF_NameTree() {} +RetainPtr<const CPDF_Array> LookupOldStyleNamedDest(CPDF_Document* pDoc, + const ByteString& name) { + RetainPtr<const CPDF_Dictionary> pDests = + pDoc->GetRoot()->GetDictFor("Dests"); + if (!pDests) + return nullptr; + return GetNamedDestFromObject(pDests->GetDirectObjectFor(name)); +} + +} // namespace + +CPDF_NameTree::CPDF_NameTree(RetainPtr<CPDF_Dictionary> pRoot) + : m_pRoot(std::move(pRoot)) { + DCHECK(m_pRoot); +} + +CPDF_NameTree::~CPDF_NameTree() = default; + +// static +std::unique_ptr<CPDF_NameTree> CPDF_NameTree::Create( + CPDF_Document* pDoc, + const ByteString& category) { + RetainPtr<CPDF_Dictionary> pRoot = pDoc->GetMutableRoot(); + if (!pRoot) + return nullptr; + + RetainPtr<CPDF_Dictionary> pNames = pRoot->GetMutableDictFor("Names"); + if (!pNames) + return nullptr; + + RetainPtr<CPDF_Dictionary> pCategory = pNames->GetMutableDictFor(category); + if (!pCategory) + return nullptr; + + return pdfium::WrapUnique( + new CPDF_NameTree(std::move(pCategory))); // Private ctor. +} + +// static +std::unique_ptr<CPDF_NameTree> CPDF_NameTree::CreateWithRootNameArray( + CPDF_Document* pDoc, + const ByteString& category) { + RetainPtr<CPDF_Dictionary> pRoot = pDoc->GetMutableRoot(); + if (!pRoot) + return nullptr; + + // Retrieve the document's Names dictionary; create it if missing. + RetainPtr<CPDF_Dictionary> pNames = pRoot->GetMutableDictFor("Names"); + if (!pNames) { + pNames = pDoc->NewIndirect<CPDF_Dictionary>(); + pRoot->SetNewFor<CPDF_Reference>("Names", pDoc, pNames->GetObjNum()); + } + + // Create the |category| dictionary if missing. + RetainPtr<CPDF_Dictionary> pCategory = pNames->GetMutableDictFor(category); + if (!pCategory) { + pCategory = pDoc->NewIndirect<CPDF_Dictionary>(); + pCategory->SetNewFor<CPDF_Array>("Names"); + pNames->SetNewFor<CPDF_Reference>(category, pDoc, pCategory->GetObjNum()); + } + + return pdfium::WrapUnique(new CPDF_NameTree(pCategory)); // Private ctor. +} + +// static +std::unique_ptr<CPDF_NameTree> CPDF_NameTree::CreateForTesting( + CPDF_Dictionary* pRoot) { + return pdfium::WrapUnique( + new CPDF_NameTree(pdfium::WrapRetain(pRoot))); // Private ctor. +} + +// static +RetainPtr<const CPDF_Array> CPDF_NameTree::LookupNamedDest( + CPDF_Document* pDoc, + const ByteString& name) { + RetainPtr<const CPDF_Array> dest_array; + std::unique_ptr<CPDF_NameTree> name_tree = Create(pDoc, "Dests"); + if (name_tree) + dest_array = name_tree->LookupNewStyleNamedDest(name); + if (!dest_array) + dest_array = LookupOldStyleNamedDest(pDoc, name); + return dest_array; +} size_t CPDF_NameTree::GetCount() const { - return m_pRoot ? CountNamesInternal(m_pRoot.Get(), 0) : 0; + std::set<const CPDF_Dictionary*> seen; + return CountNamesInternal(m_pRoot.Get(), 0, seen); } bool CPDF_NameTree::AddValueAndName(RetainPtr<CPDF_Object> pObj, const WideString& name) { - if (!m_pRoot) - return false; - - size_t nIndex = 0; - CPDF_Array* pFind = nullptr; + RetainPtr<CPDF_Array> pFind; int nFindIndex = -1; - // Fail if the tree already contains this name or if the tree is too deep. - if (SearchNameNodeByName(m_pRoot.Get(), name, 0, &nIndex, &pFind, - &nFindIndex)) { - return false; + // Handle the corner case where the root node is empty. i.e. No kids and no + // names. In which case, just insert into it and skip all the searches. + RetainPtr<CPDF_Array> pNames = m_pRoot->GetMutableArrayFor("Names"); + if (pNames && pNames->IsEmpty() && !m_pRoot->GetArrayFor("Kids")) + pFind = pNames; + + if (!pFind) { + // Fail if the tree already contains this name or if the tree is too deep. + if (SearchNameNodeByName(m_pRoot, name, &pFind, &nFindIndex)) + return false; } // If the returned |pFind| is a nullptr, then |name| is smaller than all @@ -335,96 +505,80 @@ // |name| into. We instead will find the leftmost leaf array in which to place // |name| and |pObj|. if (!pFind) { - size_t nCurIndex = 0; - WideString csName; - SearchNameNodeByIndex(m_pRoot.Get(), 0, 0, &nCurIndex, &csName, &pFind, - nullptr); + absl::optional<IndexSearchResult> result = + SearchNameNodeByIndex(m_pRoot.Get(), 0); + if (!result.has_value()) { + // Give up if that fails too. + return false; + } + + pFind = result.value().container; + DCHECK(pFind); } - // Give up if that fails too. - if (!pFind) - return false; // Insert the name and the object into the leaf array found. Note that the // insertion position is right after the key-value pair returned by |index|. size_t nNameIndex = (nFindIndex + 1) * 2; size_t nValueIndex = nNameIndex + 1; - pFind->InsertNewAt<CPDF_String>(nNameIndex, name); + pFind->InsertNewAt<CPDF_String>(nNameIndex, name.AsStringView()); pFind->InsertAt(nValueIndex, std::move(pObj)); // Expand the limits that the newly added name is under, if the name falls // outside of the limits of its leaf array or any arrays above it. - std::vector<CPDF_Array*> pLimits; - GetNodeAncestorsLimits(m_pRoot.Get(), pFind, 0, &pLimits); - for (auto* pLimit : pLimits) { - if (!pLimit) + std::vector<CPDF_Array*> all_limits = + GetNodeAncestorsLimits(m_pRoot, pFind.Get()); + for (auto* pLimits : all_limits) { + if (!pLimits) continue; - if (name.Compare(pLimit->GetUnicodeTextAt(0)) < 0) - pLimit->SetNewAt<CPDF_String>(0, name); + if (name.Compare(pLimits->GetUnicodeTextAt(0)) < 0) + pLimits->SetNewAt<CPDF_String>(0, name.AsStringView()); - if (name.Compare(pLimit->GetUnicodeTextAt(1)) > 0) - pLimit->SetNewAt<CPDF_String>(1, name); + if (name.Compare(pLimits->GetUnicodeTextAt(1)) > 0) + pLimits->SetNewAt<CPDF_String>(1, name.AsStringView()); } return true; } -bool CPDF_NameTree::DeleteValueAndName(int nIndex) { - if (!m_pRoot) - return false; - - size_t nCurIndex = 0; - WideString csName; - CPDF_Array* pFind = nullptr; - int nFindIndex = -1; - // Fail if the tree does not contain |nIndex|. - if (!SearchNameNodeByIndex(m_pRoot.Get(), nIndex, 0, &nCurIndex, &csName, - &pFind, &nFindIndex)) { +bool CPDF_NameTree::DeleteValueAndName(size_t nIndex) { + absl::optional<IndexSearchResult> result = + SearchNameNodeByIndex(m_pRoot.Get(), nIndex); + if (!result) { + // Fail if the tree does not contain |nIndex|. return false; } // Remove the name and the object from the leaf array |pFind|. - pFind->RemoveAt(nFindIndex * 2); - pFind->RemoveAt(nFindIndex * 2); + RetainPtr<CPDF_Array> pFind = result.value().container; + pFind->RemoveAt(result.value().index + 1); + pFind->RemoveAt(result.value().index); // Delete empty nodes and update the limits of |pFind|'s ancestors as needed. - UpdateNodesAndLimitsUponDeletion(m_pRoot.Get(), pFind, csName, 0); + UpdateNodesAndLimitsUponDeletion(m_pRoot.Get(), pFind.Get(), + result.value().key, 0); return true; } -CPDF_Object* CPDF_NameTree::LookupValueAndName(int nIndex, - WideString* csName) const { - csName->clear(); - if (!m_pRoot) +RetainPtr<CPDF_Object> CPDF_NameTree::LookupValueAndName( + size_t nIndex, + WideString* csName) const { + absl::optional<IndexSearchResult> result = + SearchNameNodeByIndex(m_pRoot.Get(), nIndex); + if (!result) { + csName->clear(); return nullptr; - - size_t nCurIndex = 0; - return SearchNameNodeByIndex(m_pRoot.Get(), nIndex, 0, &nCurIndex, csName, - nullptr, nullptr); -} - -CPDF_Object* CPDF_NameTree::LookupValue(const WideString& csName) const { - if (!m_pRoot) - return nullptr; - - size_t nIndex = 0; - return SearchNameNodeByName(m_pRoot.Get(), csName, 0, &nIndex, nullptr, - nullptr); -} - -CPDF_Array* CPDF_NameTree::LookupNamedDest(CPDF_Document* pDoc, - const WideString& sName) { - CPDF_Object* pValue = LookupValue(sName); - if (!pValue) { - CPDF_Dictionary* pDests = pDoc->GetRoot()->GetDictFor("Dests"); - if (!pDests) - return nullptr; - pValue = pDests->GetDirectObjectFor(PDF_EncodeText(sName)); } - if (!pValue) - return nullptr; - if (CPDF_Array* pArray = pValue->AsArray()) - return pArray; - if (CPDF_Dictionary* pDict = pValue->AsDictionary()) - return pDict->GetArrayFor("D"); - return nullptr; + + *csName = std::move(result.value().key); + return result.value().value; +} + +RetainPtr<const CPDF_Object> CPDF_NameTree::LookupValue( + const WideString& csName) const { + return SearchNameNodeByName(m_pRoot, csName, nullptr, nullptr); +} + +RetainPtr<const CPDF_Array> CPDF_NameTree::LookupNewStyleNamedDest( + const ByteString& sName) { + return GetNamedDestFromObject(LookupValue(PDF_DecodeText(sName.raw_span()))); }
diff --git a/core/fpdfdoc/cpdf_nametree.h b/core/fpdfdoc/cpdf_nametree.h index b018ae7..b40b232 100644 --- a/core/fpdfdoc/cpdf_nametree.h +++ b/core/fpdfdoc/cpdf_nametree.h
@@ -1,4 +1,4 @@ -// Copyright 2016 PDFium Authors. All rights reserved. +// Copyright 2016 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -7,6 +7,8 @@ #ifndef CORE_FPDFDOC_CPDF_NAMETREE_H_ #define CORE_FPDFDOC_CPDF_NAMETREE_H_ +#include <stddef.h> + #include <memory> #include "core/fxcrt/fx_string.h" @@ -19,22 +21,42 @@ class CPDF_NameTree { public: - explicit CPDF_NameTree(CPDF_Dictionary* pRoot); - CPDF_NameTree(CPDF_Document* pDoc, const ByteString& category); + CPDF_NameTree(const CPDF_NameTree&) = delete; + CPDF_NameTree& operator=(const CPDF_NameTree&) = delete; ~CPDF_NameTree(); - bool AddValueAndName(RetainPtr<CPDF_Object> pObj, const WideString& name); - bool DeleteValueAndName(int nIndex); + static std::unique_ptr<CPDF_NameTree> Create(CPDF_Document* pDoc, + const ByteString& category); - CPDF_Object* LookupValueAndName(int nIndex, WideString* csName) const; - CPDF_Object* LookupValue(const WideString& csName) const; - CPDF_Array* LookupNamedDest(CPDF_Document* pDoc, const WideString& sName); + // If necessary, create missing Names dictionary in |pDoc|, and/or missing + // Names array in the dictionary that corresponds to |category|, if necessary. + // Returns nullptr on failure. + static std::unique_ptr<CPDF_NameTree> CreateWithRootNameArray( + CPDF_Document* pDoc, + const ByteString& category); + + static std::unique_ptr<CPDF_NameTree> CreateForTesting( + CPDF_Dictionary* pRoot); + + static RetainPtr<const CPDF_Array> LookupNamedDest(CPDF_Document* doc, + const ByteString& name); + + bool AddValueAndName(RetainPtr<CPDF_Object> pObj, const WideString& name); + bool DeleteValueAndName(size_t nIndex); + + RetainPtr<CPDF_Object> LookupValueAndName(size_t nIndex, + WideString* csName) const; + RetainPtr<const CPDF_Object> LookupValue(const WideString& csName) const; size_t GetCount() const; - CPDF_Dictionary* GetRootForTest() const { return m_pRoot.Get(); } + CPDF_Dictionary* GetRootForTesting() const { return m_pRoot.Get(); } private: - RetainPtr<CPDF_Dictionary> m_pRoot; + explicit CPDF_NameTree(RetainPtr<CPDF_Dictionary> pRoot); + + RetainPtr<const CPDF_Array> LookupNewStyleNamedDest(const ByteString& name); + + RetainPtr<CPDF_Dictionary> const m_pRoot; }; #endif // CORE_FPDFDOC_CPDF_NAMETREE_H_
diff --git a/core/fpdfdoc/cpdf_nametree_unittest.cpp b/core/fpdfdoc/cpdf_nametree_unittest.cpp index 13b6b5c..a70359c 100644 --- a/core/fpdfdoc/cpdf_nametree_unittest.cpp +++ b/core/fpdfdoc/cpdf_nametree_unittest.cpp
@@ -1,4 +1,4 @@ -// Copyright 2017 PDFium Authors. All rights reserved. +// Copyright 2017 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -7,70 +7,96 @@ #include "core/fpdfapi/parser/cpdf_dictionary.h" #include "core/fpdfapi/parser/cpdf_number.h" #include "core/fpdfapi/parser/cpdf_string.h" +#include "core/fxcrt/retain_ptr.h" #include "testing/gtest/include/gtest/gtest.h" -#include "third_party/base/ptr_util.h" namespace { -void AddNameKeyValue(CPDF_Array* pNames, const char* key, const int value) { - pNames->AddNew<CPDF_String>(key, false); - pNames->AddNew<CPDF_Number>(value); +void AddNameKeyValue(CPDF_Array* names, const char* key, int value) { + names->AppendNew<CPDF_String>(key, false); + names->AppendNew<CPDF_Number>(value); } -void CheckNameKeyValue(CPDF_Array* pNames, - const int index, +void CheckNameKeyValue(const CPDF_Array* names, + int pair_index, const char* key, - const int value) { - EXPECT_STREQ(key, pNames->GetStringAt(index * 2).c_str()); - EXPECT_EQ(value, pNames->GetIntegerAt(index * 2 + 1)); + int value) { + ASSERT_TRUE(names); + EXPECT_STREQ(key, names->GetByteStringAt(pair_index * 2).c_str()); + EXPECT_EQ(value, names->GetIntegerAt(pair_index * 2 + 1)); } -void AddLimitsArray(CPDF_Dictionary* pNode, +void AddLimitsArray(CPDF_Dictionary* node, const char* least, const char* greatest) { - CPDF_Array* pLimits = pNode->SetNewFor<CPDF_Array>("Limits"); - pLimits->AddNew<CPDF_String>(least, false); - pLimits->AddNew<CPDF_String>(greatest, false); + auto limits = node->SetNewFor<CPDF_Array>("Limits"); + limits->AppendNew<CPDF_String>(least, false); + limits->AppendNew<CPDF_String>(greatest, false); } -void CheckLimitsArray(CPDF_Dictionary* pNode, +void CheckLimitsArray(const CPDF_Dictionary* node, const char* least, const char* greatest) { - CPDF_Array* pLimits = pNode->GetArrayFor("Limits"); - ASSERT_TRUE(pLimits); - EXPECT_STREQ(least, pLimits->GetStringAt(0).c_str()); - EXPECT_STREQ(greatest, pLimits->GetStringAt(1).c_str()); + ASSERT_TRUE(node); + RetainPtr<const CPDF_Array> limits = node->GetArrayFor("Limits"); + ASSERT_TRUE(limits); + EXPECT_EQ(2u, limits->size()); + RetainPtr<const CPDF_String> left = limits->GetStringAt(0); + ASSERT_TRUE(left); + RetainPtr<const CPDF_String> right = limits->GetStringAt(1); + ASSERT_TRUE(right); + EXPECT_STREQ(least, left->GetString().c_str()); + EXPECT_STREQ(greatest, right->GetString().c_str()); } +// Set up a name tree with 3 levels and 5 nodes, per diagram: +// +// [root] +// | +// | +// | +// [pKid1] +// | +// +------------+ +// | | +// [pGrandKid2] [pGrandKid3] +// | {9.txt: 999} +// | +// +-----------------+ +// | | +// [pGreatGrandKid4] [pGreatGrandKid5] +// {1.txt: 111} {3.txt: 333} +// {2.txt: 222} {5.txt: 555} +// void FillNameTreeDict(CPDF_Dictionary* pRootDict) { - CPDF_Array* pKids = pRootDict->SetNewFor<CPDF_Array>("Kids"); - CPDF_Dictionary* pKid1 = pKids->AddNew<CPDF_Dictionary>(); + auto pRootKids = pRootDict->SetNewFor<CPDF_Array>("Kids"); + auto pKid1 = pRootKids->AppendNew<CPDF_Dictionary>(); // Make the lower and upper limit out of order on purpose. - AddLimitsArray(pKid1, "9.txt", "1.txt"); - pKids = pKid1->SetNewFor<CPDF_Array>("Kids"); - CPDF_Dictionary* pKid2 = pKids->AddNew<CPDF_Dictionary>(); - CPDF_Dictionary* pKid3 = pKids->AddNew<CPDF_Dictionary>(); + AddLimitsArray(pKid1.Get(), "9.txt", "1.txt"); + auto pKids1Kids = pKid1->SetNewFor<CPDF_Array>("Kids"); + auto pGrandKid2 = pKids1Kids->AppendNew<CPDF_Dictionary>(); + auto pGrandKid3 = pKids1Kids->AppendNew<CPDF_Dictionary>(); - AddLimitsArray(pKid2, "1.txt", "5.txt"); - pKids = pKid2->SetNewFor<CPDF_Array>("Kids"); - CPDF_Dictionary* pKid4 = pKids->AddNew<CPDF_Dictionary>(); - CPDF_Dictionary* pKid5 = pKids->AddNew<CPDF_Dictionary>(); + AddLimitsArray(pGrandKid2.Get(), "1.txt", "5.txt"); + auto pGrandKid2Kids = pGrandKid2->SetNewFor<CPDF_Array>("Kids"); + auto pGreatGrandKid4 = pGrandKid2Kids->AppendNew<CPDF_Dictionary>(); + auto pGreatGrandKid5 = pGrandKid2Kids->AppendNew<CPDF_Dictionary>(); - AddLimitsArray(pKid3, "9.txt", "9.txt"); - CPDF_Array* pNames = pKid3->SetNewFor<CPDF_Array>("Names"); - AddNameKeyValue(pNames, "9.txt", 999); + AddLimitsArray(pGrandKid3.Get(), "9.txt", "9.txt"); + auto pNames = pGrandKid3->SetNewFor<CPDF_Array>("Names"); + AddNameKeyValue(pNames.Get(), "9.txt", 999); // Make the lower and upper limit out of order on purpose. - AddLimitsArray(pKid4, "2.txt", "1.txt"); - pNames = pKid4->SetNewFor<CPDF_Array>("Names"); - AddNameKeyValue(pNames, "1.txt", 111); - AddNameKeyValue(pNames, "2.txt", 222); + AddLimitsArray(pGreatGrandKid4.Get(), "2.txt", "1.txt"); + pNames = pGreatGrandKid4->SetNewFor<CPDF_Array>("Names"); + AddNameKeyValue(pNames.Get(), "1.txt", 111); + AddNameKeyValue(pNames.Get(), "2.txt", 222); - AddLimitsArray(pKid5, "3.txt", "5.txt"); - pNames = pKid5->SetNewFor<CPDF_Array>("Names"); - AddNameKeyValue(pNames, "3.txt", 333); - AddNameKeyValue(pNames, "5.txt", 555); + AddLimitsArray(pGreatGrandKid5.Get(), "3.txt", "5.txt"); + pNames = pGreatGrandKid5->SetNewFor<CPDF_Array>("Names"); + AddNameKeyValue(pNames.Get(), "3.txt", 333); + AddNameKeyValue(pNames.Get(), "5.txt", 555); } } // namespace @@ -78,221 +104,283 @@ TEST(cpdf_nametree, GetUnicodeNameWithBOM) { // Set up the root dictionary with a Names array. auto pRootDict = pdfium::MakeRetain<CPDF_Dictionary>(); - CPDF_Array* pNames = pRootDict->SetNewFor<CPDF_Array>("Names"); + auto pNames = pRootDict->SetNewFor<CPDF_Array>("Names"); // Add the key "1" (with BOM) and value 100 into the array. - std::ostringstream buf; constexpr char kData[] = "\xFE\xFF\x00\x31"; - for (size_t i = 0; i < sizeof(kData); ++i) - buf.put(kData[i]); - pNames->AddNew<CPDF_String>(ByteString(buf), true); - pNames->AddNew<CPDF_Number>(100); + pNames->AppendNew<CPDF_String>(ByteString(kData, sizeof(kData) - 1), true); + pNames->AppendNew<CPDF_Number>(100); // Check that the key is as expected. - CPDF_NameTree nameTree(pRootDict.Get()); - WideString storedName; - nameTree.LookupValueAndName(0, &storedName); - EXPECT_STREQ(L"1", storedName.c_str()); + std::unique_ptr<CPDF_NameTree> name_tree = + CPDF_NameTree::CreateForTesting(pRootDict.Get()); + WideString stored_name; + name_tree->LookupValueAndName(0, &stored_name); + EXPECT_STREQ(L"1", stored_name.c_str()); // Check that the correct value object can be obtained by looking up "1". - WideString matchName = L"1"; - CPDF_Object* pObj = nameTree.LookupValue(matchName); - ASSERT_TRUE(pObj->IsNumber()); - EXPECT_EQ(100, pObj->AsNumber()->GetInteger()); + RetainPtr<const CPDF_Number> pNumber = ToNumber(name_tree->LookupValue(L"1")); + ASSERT_TRUE(pNumber); + EXPECT_EQ(100, pNumber->GetInteger()); +} + +TEST(cpdf_nametree, GetFromTreeWithLimitsArrayWith4Items) { + // After creating a name tree, mutate a /Limits array so it has excess + // elements. + auto pRootDict = pdfium::MakeRetain<CPDF_Dictionary>(); + FillNameTreeDict(pRootDict.Get()); + RetainPtr<CPDF_Dictionary> pKid1 = + pRootDict->GetMutableArrayFor("Kids")->GetMutableDictAt(0); + RetainPtr<CPDF_Dictionary> pGrandKid3 = + pKid1->GetMutableArrayFor("Kids")->GetMutableDictAt(1); + RetainPtr<CPDF_Array> pLimits = pGrandKid3->GetMutableArrayFor("Limits"); + ASSERT_EQ(2u, pLimits->size()); + pLimits->AppendNew<CPDF_Number>(5); + pLimits->AppendNew<CPDF_Number>(6); + ASSERT_EQ(4u, pLimits->size()); + std::unique_ptr<CPDF_NameTree> name_tree = + CPDF_NameTree::CreateForTesting(pRootDict.Get()); + + RetainPtr<const CPDF_Number> pNumber = + ToNumber(name_tree->LookupValue(L"9.txt")); + ASSERT_TRUE(pNumber); + EXPECT_EQ(999, pNumber->GetInteger()); + CheckLimitsArray(pKid1.Get(), "1.txt", "9.txt"); + CheckLimitsArray(pGrandKid3.Get(), "9.txt", "9.txt"); } TEST(cpdf_nametree, AddIntoNames) { // Set up a name tree with a single Names array. auto pRootDict = pdfium::MakeRetain<CPDF_Dictionary>(); - CPDF_Array* pNames = pRootDict->SetNewFor<CPDF_Array>("Names"); - AddNameKeyValue(pNames, "2.txt", 222); - AddNameKeyValue(pNames, "7.txt", 777); + auto pNames = pRootDict->SetNewFor<CPDF_Array>("Names"); + AddNameKeyValue(pNames.Get(), "2.txt", 222); + AddNameKeyValue(pNames.Get(), "7.txt", 777); - CPDF_NameTree nameTree(pRootDict.Get()); - pNames = nameTree.GetRootForTest()->GetArrayFor("Names"); + std::unique_ptr<CPDF_NameTree> name_tree = + CPDF_NameTree::CreateForTesting(pRootDict.Get()); // Insert a name that already exists in the names array. - EXPECT_FALSE( - nameTree.AddValueAndName(pdfium::MakeRetain<CPDF_Number>(111), L"2.txt")); + EXPECT_FALSE(name_tree->AddValueAndName(pdfium::MakeRetain<CPDF_Number>(111), + L"2.txt")); // Insert in the beginning of the names array. - EXPECT_TRUE( - nameTree.AddValueAndName(pdfium::MakeRetain<CPDF_Number>(111), L"1.txt")); + EXPECT_TRUE(name_tree->AddValueAndName(pdfium::MakeRetain<CPDF_Number>(111), + L"1.txt")); // Insert in the middle of the names array. - EXPECT_TRUE( - nameTree.AddValueAndName(pdfium::MakeRetain<CPDF_Number>(555), L"5.txt")); + EXPECT_TRUE(name_tree->AddValueAndName(pdfium::MakeRetain<CPDF_Number>(555), + L"5.txt")); // Insert at the end of the names array. - EXPECT_TRUE( - nameTree.AddValueAndName(pdfium::MakeRetain<CPDF_Number>(999), L"9.txt")); + EXPECT_TRUE(name_tree->AddValueAndName(pdfium::MakeRetain<CPDF_Number>(999), + L"9.txt")); // Check that the names array has the expected key-value pairs. - CheckNameKeyValue(pNames, 0, "1.txt", 111); - CheckNameKeyValue(pNames, 1, "2.txt", 222); - CheckNameKeyValue(pNames, 2, "5.txt", 555); - CheckNameKeyValue(pNames, 3, "7.txt", 777); - CheckNameKeyValue(pNames, 4, "9.txt", 999); + CheckNameKeyValue(pNames.Get(), 0, "1.txt", 111); + CheckNameKeyValue(pNames.Get(), 1, "2.txt", 222); + CheckNameKeyValue(pNames.Get(), 2, "5.txt", 555); + CheckNameKeyValue(pNames.Get(), 3, "7.txt", 777); + CheckNameKeyValue(pNames.Get(), 4, "9.txt", 999); +} + +TEST(cpdf_nametree, AddIntoEmptyNames) { + // Set up a name tree with an empty Names array. + auto pRootDict = pdfium::MakeRetain<CPDF_Dictionary>(); + auto pNames = pRootDict->SetNewFor<CPDF_Array>("Names"); + + std::unique_ptr<CPDF_NameTree> name_tree = + CPDF_NameTree::CreateForTesting(pRootDict.Get()); + + // Insert a name should work. + EXPECT_TRUE(name_tree->AddValueAndName(pdfium::MakeRetain<CPDF_Number>(111), + L"2.txt")); + + // Insert a name that already exists in the names array. + EXPECT_FALSE(name_tree->AddValueAndName(pdfium::MakeRetain<CPDF_Number>(111), + L"2.txt")); + + // Insert in the beginning of the names array. + EXPECT_TRUE(name_tree->AddValueAndName(pdfium::MakeRetain<CPDF_Number>(111), + L"1.txt")); + + // Insert in the middle of the names array. + EXPECT_TRUE(name_tree->AddValueAndName(pdfium::MakeRetain<CPDF_Number>(555), + L"5.txt")); + + // Insert at the end of the names array. + EXPECT_TRUE(name_tree->AddValueAndName(pdfium::MakeRetain<CPDF_Number>(999), + L"9.txt")); + + // Check that the names array has the expected key-value pairs. + CheckNameKeyValue(pNames.Get(), 0, "1.txt", 111); + CheckNameKeyValue(pNames.Get(), 1, "2.txt", 111); + CheckNameKeyValue(pNames.Get(), 2, "5.txt", 555); + CheckNameKeyValue(pNames.Get(), 3, "9.txt", 999); } TEST(cpdf_nametree, AddIntoKids) { - // Set up a name tree with five nodes of three levels. auto pRootDict = pdfium::MakeRetain<CPDF_Dictionary>(); FillNameTreeDict(pRootDict.Get()); - CPDF_NameTree nameTree(pRootDict.Get()); + std::unique_ptr<CPDF_NameTree> name_tree = + CPDF_NameTree::CreateForTesting(pRootDict.Get()); // Check that adding an existing name would fail. - EXPECT_FALSE( - nameTree.AddValueAndName(pdfium::MakeRetain<CPDF_Number>(444), L"9.txt")); + EXPECT_FALSE(name_tree->AddValueAndName(pdfium::MakeRetain<CPDF_Number>(444), + L"9.txt")); // Add a name within the limits of a leaf node. - EXPECT_TRUE( - nameTree.AddValueAndName(pdfium::MakeRetain<CPDF_Number>(444), L"4.txt")); - ASSERT_TRUE(nameTree.LookupValue(L"4.txt")); - EXPECT_EQ(444, nameTree.LookupValue(L"4.txt")->GetInteger()); + EXPECT_TRUE(name_tree->AddValueAndName(pdfium::MakeRetain<CPDF_Number>(444), + L"4.txt")); + ASSERT_TRUE(name_tree->LookupValue(L"4.txt")); + EXPECT_EQ(444, name_tree->LookupValue(L"4.txt")->GetInteger()); // Add a name that requires changing the limits of two bottom levels. - EXPECT_TRUE( - nameTree.AddValueAndName(pdfium::MakeRetain<CPDF_Number>(666), L"6.txt")); - ASSERT_TRUE(nameTree.LookupValue(L"6.txt")); - EXPECT_EQ(666, nameTree.LookupValue(L"6.txt")->GetInteger()); + EXPECT_TRUE(name_tree->AddValueAndName(pdfium::MakeRetain<CPDF_Number>(666), + L"6.txt")); + ASSERT_TRUE(name_tree->LookupValue(L"6.txt")); + EXPECT_EQ(666, name_tree->LookupValue(L"6.txt")->GetInteger()); // Add a name that requires changing the limits of two top levels. - EXPECT_TRUE( - nameTree.AddValueAndName(pdfium::MakeRetain<CPDF_Number>(99), L"99.txt")); - ASSERT_TRUE(nameTree.LookupValue(L"99.txt")); - EXPECT_EQ(99, nameTree.LookupValue(L"99.txt")->GetInteger()); + EXPECT_TRUE(name_tree->AddValueAndName(pdfium::MakeRetain<CPDF_Number>(99), + L"99.txt")); + ASSERT_TRUE(name_tree->LookupValue(L"99.txt")); + EXPECT_EQ(99, name_tree->LookupValue(L"99.txt")->GetInteger()); // Add a name that requires changing the lower limit of all levels. - EXPECT_TRUE( - nameTree.AddValueAndName(pdfium::MakeRetain<CPDF_Number>(-5), L"0.txt")); - ASSERT_TRUE(nameTree.LookupValue(L"0.txt")); - EXPECT_EQ(-5, nameTree.LookupValue(L"0.txt")->GetInteger()); + EXPECT_TRUE(name_tree->AddValueAndName(pdfium::MakeRetain<CPDF_Number>(-5), + L"0.txt")); + ASSERT_TRUE(name_tree->LookupValue(L"0.txt")); + EXPECT_EQ(-5, name_tree->LookupValue(L"0.txt")->GetInteger()); // Check that the node on the first level has the expected limits. - CPDF_Dictionary* pKid1 = - nameTree.GetRootForTest()->GetArrayFor("Kids")->GetDictAt(0); + RetainPtr<const CPDF_Dictionary> pKid1 = + name_tree->GetRootForTesting()->GetArrayFor("Kids")->GetDictAt(0); ASSERT_TRUE(pKid1); - CheckLimitsArray(pKid1, "0.txt", "99.txt"); + CheckLimitsArray(pKid1.Get(), "0.txt", "99.txt"); // Check that the nodes on the second level has the expected limits and names. - CPDF_Dictionary* pKid2 = pKid1->GetArrayFor("Kids")->GetDictAt(0); - ASSERT_TRUE(pKid2); - CheckLimitsArray(pKid2, "0.txt", "6.txt"); + RetainPtr<const CPDF_Dictionary> pGrandKid2 = + pKid1->GetArrayFor("Kids")->GetDictAt(0); + ASSERT_TRUE(pGrandKid2); + CheckLimitsArray(pGrandKid2.Get(), "0.txt", "6.txt"); - CPDF_Dictionary* pKid3 = pKid1->GetArrayFor("Kids")->GetDictAt(1); - ASSERT_TRUE(pKid3); - CheckLimitsArray(pKid3, "9.txt", "99.txt"); - CPDF_Array* pNames = pKid3->GetArrayFor("Names"); - ASSERT_TRUE(pNames); - CheckNameKeyValue(pNames, 0, "9.txt", 999); - CheckNameKeyValue(pNames, 1, "99.txt", 99); + RetainPtr<const CPDF_Dictionary> pGrandKid3 = + pKid1->GetArrayFor("Kids")->GetDictAt(1); + ASSERT_TRUE(pGrandKid3); + CheckLimitsArray(pGrandKid3.Get(), "9.txt", "99.txt"); + RetainPtr<const CPDF_Array> pNames = pGrandKid3->GetArrayFor("Names"); + CheckNameKeyValue(pNames.Get(), 0, "9.txt", 999); + CheckNameKeyValue(pNames.Get(), 1, "99.txt", 99); // Check that the nodes on the third level has the expected limits and names. - CPDF_Dictionary* pKid4 = pKid2->GetArrayFor("Kids")->GetDictAt(0); - ASSERT_TRUE(pKid4); - CheckLimitsArray(pKid4, "0.txt", "2.txt"); - pNames = pKid4->GetArrayFor("Names"); - ASSERT_TRUE(pNames); - CheckNameKeyValue(pNames, 0, "0.txt", -5); - CheckNameKeyValue(pNames, 1, "1.txt", 111); - CheckNameKeyValue(pNames, 2, "2.txt", 222); + RetainPtr<const CPDF_Dictionary> pGreatGrandKid4 = + pGrandKid2->GetArrayFor("Kids")->GetDictAt(0); + ASSERT_TRUE(pGreatGrandKid4); + CheckLimitsArray(pGreatGrandKid4.Get(), "0.txt", "2.txt"); + pNames = pGreatGrandKid4->GetArrayFor("Names"); + CheckNameKeyValue(pNames.Get(), 0, "0.txt", -5); + CheckNameKeyValue(pNames.Get(), 1, "1.txt", 111); + CheckNameKeyValue(pNames.Get(), 2, "2.txt", 222); - CPDF_Dictionary* pKid5 = pKid2->GetArrayFor("Kids")->GetDictAt(1); - ASSERT_TRUE(pKid5); - CheckLimitsArray(pKid5, "3.txt", "6.txt"); - pNames = pKid5->GetArrayFor("Names"); - ASSERT_TRUE(pNames); - CheckNameKeyValue(pNames, 0, "3.txt", 333); - CheckNameKeyValue(pNames, 1, "4.txt", 444); - CheckNameKeyValue(pNames, 2, "5.txt", 555); - CheckNameKeyValue(pNames, 3, "6.txt", 666); + RetainPtr<const CPDF_Dictionary> pGreatGrandKid5 = + pGrandKid2->GetArrayFor("Kids")->GetDictAt(1); + ASSERT_TRUE(pGreatGrandKid5); + CheckLimitsArray(pGreatGrandKid5.Get(), "3.txt", "6.txt"); + pNames = pGreatGrandKid5->GetArrayFor("Names"); + CheckNameKeyValue(pNames.Get(), 0, "3.txt", 333); + CheckNameKeyValue(pNames.Get(), 1, "4.txt", 444); + CheckNameKeyValue(pNames.Get(), 2, "5.txt", 555); + CheckNameKeyValue(pNames.Get(), 3, "6.txt", 666); } TEST(cpdf_nametree, DeleteFromKids) { - // Set up a name tree with five nodes of three levels. auto pRootDict = pdfium::MakeRetain<CPDF_Dictionary>(); FillNameTreeDict(pRootDict.Get()); - CPDF_NameTree nameTree(pRootDict.Get()); + std::unique_ptr<CPDF_NameTree> name_tree = + CPDF_NameTree::CreateForTesting(pRootDict.Get()); // Retrieve the kid dictionaries. - CPDF_Dictionary* pKid1 = - nameTree.GetRootForTest()->GetArrayFor("Kids")->GetDictAt(0); + RetainPtr<const CPDF_Dictionary> pKid1 = + name_tree->GetRootForTesting()->GetArrayFor("Kids")->GetDictAt(0); ASSERT_TRUE(pKid1); - CPDF_Dictionary* pKid2 = pKid1->GetArrayFor("Kids")->GetDictAt(0); - ASSERT_TRUE(pKid2); - CPDF_Dictionary* pKid3 = pKid1->GetArrayFor("Kids")->GetDictAt(1); - ASSERT_TRUE(pKid3); - CPDF_Dictionary* pKid4 = pKid2->GetArrayFor("Kids")->GetDictAt(0); - ASSERT_TRUE(pKid4); - CPDF_Dictionary* pKid5 = pKid2->GetArrayFor("Kids")->GetDictAt(1); - ASSERT_TRUE(pKid5); + RetainPtr<const CPDF_Dictionary> pGrandKid2 = + pKid1->GetArrayFor("Kids")->GetDictAt(0); + ASSERT_TRUE(pGrandKid2); + RetainPtr<const CPDF_Dictionary> pGrandKid3 = + pKid1->GetArrayFor("Kids")->GetDictAt(1); + ASSERT_TRUE(pGrandKid3); + RetainPtr<const CPDF_Dictionary> pGreatGrandKid4 = + pGrandKid2->GetArrayFor("Kids")->GetDictAt(0); + ASSERT_TRUE(pGreatGrandKid4); + RetainPtr<const CPDF_Dictionary> pGreatGrandKid5 = + pGrandKid2->GetArrayFor("Kids")->GetDictAt(1); + ASSERT_TRUE(pGreatGrandKid5); // Check that deleting an out-of-bound index would fail. - EXPECT_FALSE(nameTree.DeleteValueAndName(5)); + EXPECT_FALSE(name_tree->DeleteValueAndName(5)); // Delete the name "9.txt", and check that its node gets deleted and its // parent node's limits get updated. WideString csName; - ASSERT_TRUE(nameTree.LookupValue(L"9.txt")); - EXPECT_EQ(999, nameTree.LookupValue(L"9.txt")->GetInteger()); - EXPECT_TRUE(nameTree.LookupValueAndName(4, &csName)); + ASSERT_TRUE(name_tree->LookupValue(L"9.txt")); + EXPECT_EQ(999, name_tree->LookupValue(L"9.txt")->GetInteger()); + EXPECT_TRUE(name_tree->LookupValueAndName(4, &csName)); EXPECT_STREQ(L"9.txt", csName.c_str()); EXPECT_EQ(2u, pKid1->GetArrayFor("Kids")->size()); - EXPECT_TRUE(nameTree.DeleteValueAndName(4)); + EXPECT_TRUE(name_tree->DeleteValueAndName(4)); EXPECT_EQ(1u, pKid1->GetArrayFor("Kids")->size()); - CheckLimitsArray(pKid1, "1.txt", "5.txt"); + CheckLimitsArray(pKid1.Get(), "1.txt", "5.txt"); // Delete the name "2.txt", and check that its node does not get deleted, its // node's limits get updated, and no other limits get updated. - ASSERT_TRUE(nameTree.LookupValue(L"2.txt")); - EXPECT_EQ(222, nameTree.LookupValue(L"2.txt")->GetInteger()); - EXPECT_TRUE(nameTree.LookupValueAndName(1, &csName)); + ASSERT_TRUE(name_tree->LookupValue(L"2.txt")); + EXPECT_EQ(222, name_tree->LookupValue(L"2.txt")->GetInteger()); + EXPECT_TRUE(name_tree->LookupValueAndName(1, &csName)); EXPECT_STREQ(L"2.txt", csName.c_str()); - EXPECT_EQ(4u, pKid4->GetArrayFor("Names")->size()); - EXPECT_TRUE(nameTree.DeleteValueAndName(1)); - EXPECT_EQ(2u, pKid4->GetArrayFor("Names")->size()); - CheckLimitsArray(pKid4, "1.txt", "1.txt"); - CheckLimitsArray(pKid2, "1.txt", "5.txt"); - CheckLimitsArray(pKid1, "1.txt", "5.txt"); + EXPECT_EQ(4u, pGreatGrandKid4->GetArrayFor("Names")->size()); + EXPECT_TRUE(name_tree->DeleteValueAndName(1)); + EXPECT_EQ(2u, pGreatGrandKid4->GetArrayFor("Names")->size()); + CheckLimitsArray(pGreatGrandKid4.Get(), "1.txt", "1.txt"); + CheckLimitsArray(pGrandKid2.Get(), "1.txt", "5.txt"); + CheckLimitsArray(pKid1.Get(), "1.txt", "5.txt"); // Delete the name "1.txt", and check that its node gets deleted, and its // parent's and gradparent's limits get updated. - ASSERT_TRUE(nameTree.LookupValue(L"1.txt")); - EXPECT_EQ(111, nameTree.LookupValue(L"1.txt")->GetInteger()); - EXPECT_TRUE(nameTree.LookupValueAndName(0, &csName)); + ASSERT_TRUE(name_tree->LookupValue(L"1.txt")); + EXPECT_EQ(111, name_tree->LookupValue(L"1.txt")->GetInteger()); + EXPECT_TRUE(name_tree->LookupValueAndName(0, &csName)); EXPECT_STREQ(L"1.txt", csName.c_str()); - EXPECT_EQ(2u, pKid2->GetArrayFor("Kids")->size()); - EXPECT_TRUE(nameTree.DeleteValueAndName(0)); - EXPECT_EQ(1u, pKid2->GetArrayFor("Kids")->size()); - CheckLimitsArray(pKid2, "3.txt", "5.txt"); - CheckLimitsArray(pKid1, "3.txt", "5.txt"); + EXPECT_EQ(2u, pGrandKid2->GetArrayFor("Kids")->size()); + EXPECT_TRUE(name_tree->DeleteValueAndName(0)); + EXPECT_EQ(1u, pGrandKid2->GetArrayFor("Kids")->size()); + CheckLimitsArray(pGrandKid2.Get(), "3.txt", "5.txt"); + CheckLimitsArray(pKid1.Get(), "3.txt", "5.txt"); // Delete the name "3.txt", and check that its node does not get deleted, and // its node's, its parent's, and its grandparent's limits get updated. - ASSERT_TRUE(nameTree.LookupValue(L"3.txt")); - EXPECT_EQ(333, nameTree.LookupValue(L"3.txt")->GetInteger()); - EXPECT_TRUE(nameTree.LookupValueAndName(0, &csName)); + ASSERT_TRUE(name_tree->LookupValue(L"3.txt")); + EXPECT_EQ(333, name_tree->LookupValue(L"3.txt")->GetInteger()); + EXPECT_TRUE(name_tree->LookupValueAndName(0, &csName)); EXPECT_STREQ(L"3.txt", csName.c_str()); - EXPECT_EQ(4u, pKid5->GetArrayFor("Names")->size()); - EXPECT_TRUE(nameTree.DeleteValueAndName(0)); - EXPECT_EQ(2u, pKid5->GetArrayFor("Names")->size()); - CheckLimitsArray(pKid5, "5.txt", "5.txt"); - CheckLimitsArray(pKid2, "5.txt", "5.txt"); - CheckLimitsArray(pKid1, "5.txt", "5.txt"); + EXPECT_EQ(4u, pGreatGrandKid5->GetArrayFor("Names")->size()); + EXPECT_TRUE(name_tree->DeleteValueAndName(0)); + EXPECT_EQ(2u, pGreatGrandKid5->GetArrayFor("Names")->size()); + CheckLimitsArray(pGreatGrandKid5.Get(), "5.txt", "5.txt"); + CheckLimitsArray(pGrandKid2.Get(), "5.txt", "5.txt"); + CheckLimitsArray(pKid1.Get(), "5.txt", "5.txt"); // Delete the name "5.txt", and check that all nodes in the tree get deleted // since they are now all empty. - ASSERT_TRUE(nameTree.LookupValue(L"5.txt")); - EXPECT_EQ(555, nameTree.LookupValue(L"5.txt")->GetInteger()); - EXPECT_TRUE(nameTree.LookupValueAndName(0, &csName)); + ASSERT_TRUE(name_tree->LookupValue(L"5.txt")); + EXPECT_EQ(555, name_tree->LookupValue(L"5.txt")->GetInteger()); + EXPECT_TRUE(name_tree->LookupValueAndName(0, &csName)); EXPECT_STREQ(L"5.txt", csName.c_str()); - EXPECT_EQ(1u, nameTree.GetRootForTest()->GetArrayFor("Kids")->size()); - EXPECT_TRUE(nameTree.DeleteValueAndName(0)); - EXPECT_EQ(0u, nameTree.GetRootForTest()->GetArrayFor("Kids")->size()); + EXPECT_EQ(1u, name_tree->GetRootForTesting()->GetArrayFor("Kids")->size()); + EXPECT_TRUE(name_tree->DeleteValueAndName(0)); + EXPECT_EQ(0u, name_tree->GetRootForTesting()->GetArrayFor("Kids")->size()); // Check that the tree is now empty. - EXPECT_EQ(0u, nameTree.GetCount()); - EXPECT_FALSE(nameTree.LookupValueAndName(0, &csName)); - EXPECT_FALSE(nameTree.DeleteValueAndName(0)); + EXPECT_EQ(0u, name_tree->GetCount()); + EXPECT_FALSE(name_tree->LookupValueAndName(0, &csName)); + EXPECT_FALSE(name_tree->DeleteValueAndName(0)); }
diff --git a/core/fpdfdoc/cpdf_numbertree.cpp b/core/fpdfdoc/cpdf_numbertree.cpp index 46257c8..f381634 100644 --- a/core/fpdfdoc/cpdf_numbertree.cpp +++ b/core/fpdfdoc/cpdf_numbertree.cpp
@@ -1,4 +1,4 @@ -// Copyright 2016 PDFium Authors. All rights reserved. +// Copyright 2016 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -6,18 +6,21 @@ #include "core/fpdfdoc/cpdf_numbertree.h" +#include <utility> + #include "core/fpdfapi/parser/cpdf_array.h" #include "core/fpdfapi/parser/cpdf_dictionary.h" namespace { -const CPDF_Object* SearchNumberNode(const CPDF_Dictionary* pNode, int num) { - const CPDF_Array* pLimits = pNode->GetArrayFor("Limits"); +RetainPtr<const CPDF_Object> SearchNumberNode(const CPDF_Dictionary* pNode, + int num) { + RetainPtr<const CPDF_Array> pLimits = pNode->GetArrayFor("Limits"); if (pLimits && (num < pLimits->GetIntegerAt(0) || num > pLimits->GetIntegerAt(1))) { return nullptr; } - const CPDF_Array* pNumbers = pNode->GetArrayFor("Nums"); + RetainPtr<const CPDF_Array> pNumbers = pNode->GetArrayFor("Nums"); if (pNumbers) { for (size_t i = 0; i < pNumbers->size() / 2; i++) { int index = pNumbers->GetIntegerAt(i * 2); @@ -29,16 +32,16 @@ return nullptr; } - const CPDF_Array* pKids = pNode->GetArrayFor("Kids"); + RetainPtr<const CPDF_Array> pKids = pNode->GetArrayFor("Kids"); if (!pKids) return nullptr; for (size_t i = 0; i < pKids->size(); i++) { - const CPDF_Dictionary* pKid = pKids->GetDictAt(i); + RetainPtr<const CPDF_Dictionary> pKid = pKids->GetDictAt(i); if (!pKid) continue; - const CPDF_Object* pFound = SearchNumberNode(pKid, num); + RetainPtr<const CPDF_Object> pFound = SearchNumberNode(pKid.Get(), num); if (pFound) return pFound; } @@ -47,11 +50,11 @@ } // namespace -CPDF_NumberTree::CPDF_NumberTree(const CPDF_Dictionary* pRoot) - : m_pRoot(pRoot) {} +CPDF_NumberTree::CPDF_NumberTree(RetainPtr<const CPDF_Dictionary> pRoot) + : m_pRoot(std::move(pRoot)) {} -CPDF_NumberTree::~CPDF_NumberTree() {} +CPDF_NumberTree::~CPDF_NumberTree() = default; -const CPDF_Object* CPDF_NumberTree::LookupValue(int num) const { +RetainPtr<const CPDF_Object> CPDF_NumberTree::LookupValue(int num) const { return SearchNumberNode(m_pRoot.Get(), num); }
diff --git a/core/fpdfdoc/cpdf_numbertree.h b/core/fpdfdoc/cpdf_numbertree.h index 2a3fa6e..1cd1ef8 100644 --- a/core/fpdfdoc/cpdf_numbertree.h +++ b/core/fpdfdoc/cpdf_numbertree.h
@@ -1,4 +1,4 @@ -// Copyright 2016 PDFium Authors. All rights reserved. +// Copyright 2016 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -14,10 +14,10 @@ class CPDF_NumberTree { public: - explicit CPDF_NumberTree(const CPDF_Dictionary* pRoot); + explicit CPDF_NumberTree(RetainPtr<const CPDF_Dictionary> pRoot); ~CPDF_NumberTree(); - const CPDF_Object* LookupValue(int num) const; + RetainPtr<const CPDF_Object> LookupValue(int num) const; protected: RetainPtr<const CPDF_Dictionary> const m_pRoot;
diff --git a/core/fpdfdoc/cpdf_pagelabel.cpp b/core/fpdfdoc/cpdf_pagelabel.cpp index 8985def..2611936 100644 --- a/core/fpdfdoc/cpdf_pagelabel.cpp +++ b/core/fpdfdoc/cpdf_pagelabel.cpp
@@ -1,4 +1,4 @@ -// Copyright 2016 PDFium Authors. All rights reserved. +// Copyright 2016 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -6,6 +6,8 @@ #include "core/fpdfdoc/cpdf_pagelabel.h" +#include <utility> + #include "core/fpdfapi/parser/cpdf_dictionary.h" #include "core/fpdfapi/parser/cpdf_document.h" #include "core/fpdfapi/parser/fpdf_parser_decode.h" @@ -15,8 +17,9 @@ WideString MakeRoman(int num) { const int kArabic[] = {1000, 900, 500, 400, 100, 90, 50, 40, 10, 9, 5, 4, 1}; - const WideString kRoman[] = {L"m", L"cm", L"d", L"cd", L"c", L"xc", L"l", - L"xl", L"x", L"ix", L"v", L"iv", L"i"}; + const WideStringView kRoman[] = {L"m", L"cm", L"d", L"cd", L"c", + L"xc", L"l", L"xl", L"x", L"ix", + L"v", L"iv", L"i"}; const int kMaxNum = 1000000; num %= kMaxNum; @@ -53,7 +56,7 @@ if (bsStyle.IsEmpty()) return WideString(); if (bsStyle == "D") - return WideString::Format(L"%d", num); + return WideString::FormatInteger(num); if (bsStyle == "R") { WideString wsNumPortion = MakeRoman(num); wsNumPortion.MakeUpper(); @@ -76,25 +79,25 @@ CPDF_PageLabel::CPDF_PageLabel(CPDF_Document* pDocument) : m_pDocument(pDocument) {} -CPDF_PageLabel::~CPDF_PageLabel() {} +CPDF_PageLabel::~CPDF_PageLabel() = default; -Optional<WideString> CPDF_PageLabel::GetLabel(int nPage) const { +absl::optional<WideString> CPDF_PageLabel::GetLabel(int nPage) const { if (!m_pDocument) - return {}; + return absl::nullopt; if (nPage < 0 || nPage >= m_pDocument->GetPageCount()) - return {}; + return absl::nullopt; const CPDF_Dictionary* pPDFRoot = m_pDocument->GetRoot(); if (!pPDFRoot) - return {}; + return absl::nullopt; - const CPDF_Dictionary* pLabels = pPDFRoot->GetDictFor("PageLabels"); + RetainPtr<const CPDF_Dictionary> pLabels = pPDFRoot->GetDictFor("PageLabels"); if (!pLabels) - return {}; + return absl::nullopt; - CPDF_NumberTree numberTree(pLabels); - const CPDF_Object* pValue = nullptr; + CPDF_NumberTree numberTree(std::move(pLabels)); + RetainPtr<const CPDF_Object> pValue; int n = nPage; while (n >= 0) { pValue = numberTree.LookupValue(n); @@ -103,20 +106,19 @@ n--; } - WideString label; if (pValue) { pValue = pValue->GetDirect(); if (const CPDF_Dictionary* pLabel = pValue->AsDictionary()) { + WideString label; if (pLabel->KeyExist("P")) label += pLabel->GetUnicodeTextFor("P"); - ByteString bsNumberingStyle = pLabel->GetStringFor("S", ByteString()); + ByteString bsNumberingStyle = pLabel->GetByteStringFor("S", ByteString()); int nLabelNum = nPage - n + pLabel->GetIntegerFor("St", 1); WideString wsNumPortion = GetLabelNumPortion(nLabelNum, bsNumberingStyle); label += wsNumPortion; - return {label}; + return label; } } - label = WideString::Format(L"%d", nPage + 1); - return {label}; + return WideString::FormatInteger(nPage + 1); }
diff --git a/core/fpdfdoc/cpdf_pagelabel.h b/core/fpdfdoc/cpdf_pagelabel.h index 473485d..05ec237 100644 --- a/core/fpdfdoc/cpdf_pagelabel.h +++ b/core/fpdfdoc/cpdf_pagelabel.h
@@ -1,4 +1,4 @@ -// Copyright 2016 PDFium Authors. All rights reserved. +// Copyright 2016 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -7,8 +7,9 @@ #ifndef CORE_FPDFDOC_CPDF_PAGELABEL_H_ #define CORE_FPDFDOC_CPDF_PAGELABEL_H_ -#include "core/fxcrt/fx_string.h" -#include "third_party/base/optional.h" +#include "core/fxcrt/unowned_ptr.h" +#include "core/fxcrt/widestring.h" +#include "third_party/abseil-cpp/absl/types/optional.h" class CPDF_Document; @@ -17,7 +18,7 @@ explicit CPDF_PageLabel(CPDF_Document* pDocument); ~CPDF_PageLabel(); - Optional<WideString> GetLabel(int nPage) const; + absl::optional<WideString> GetLabel(int nPage) const; private: UnownedPtr<CPDF_Document> const m_pDocument;
diff --git a/core/fpdfdoc/cpdf_structelement.cpp b/core/fpdfdoc/cpdf_structelement.cpp index 40477b4..b28774d 100644 --- a/core/fpdfdoc/cpdf_structelement.cpp +++ b/core/fpdfdoc/cpdf_structelement.cpp
@@ -1,4 +1,4 @@ -// Copyright 2017 PDFium Authors. All rights reserved. +// Copyright 2017 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -16,46 +16,66 @@ #include "core/fpdfapi/parser/cpdf_reference.h" #include "core/fpdfapi/parser/cpdf_stream.h" #include "core/fpdfdoc/cpdf_structtree.h" +#include "third_party/base/check.h" -namespace { +CPDF_StructElement::Kid::Kid() = default; -ByteString GetStructElementType(CPDF_StructTree* pTree, - const CPDF_Dictionary* pDict) { - ByteString type = pDict->GetStringFor("S"); - if (pTree->GetRoleMap()) { - ByteString mapped = pTree->GetRoleMap()->GetStringFor(type); - if (!mapped.IsEmpty()) - type = std::move(mapped); - } - return type; -} +CPDF_StructElement::Kid::Kid(const Kid& that) = default; -} // namespace +CPDF_StructElement::Kid::~Kid() = default; -CPDF_StructKid::CPDF_StructKid() = default; - -CPDF_StructKid::CPDF_StructKid(const CPDF_StructKid& that) = default; - -CPDF_StructKid::~CPDF_StructKid() = default; - -CPDF_StructElement::CPDF_StructElement(CPDF_StructTree* pTree, - CPDF_StructElement* pParent, - const CPDF_Dictionary* pDict) +CPDF_StructElement::CPDF_StructElement(const CPDF_StructTree* pTree, + RetainPtr<const CPDF_Dictionary> pDict) : m_pTree(pTree), - m_pParent(pParent), - m_pDict(pDict), - m_Type(GetStructElementType(m_pTree.Get(), m_pDict.Get())) { - LoadKids(m_pDict.Get()); + m_pDict(std::move(pDict)), + m_Type(m_pTree->GetRoleMapNameFor(m_pDict->GetNameFor("S"))) { + LoadKids(m_pDict); } -CPDF_StructElement::~CPDF_StructElement() = default; +CPDF_StructElement::~CPDF_StructElement() { + for (auto& kid : m_Kids) { + if (kid.m_Type == Kid::kElement && kid.m_pElement) { + kid.m_pElement->SetParent(nullptr); + } + } +} + +ByteString CPDF_StructElement::GetObjType() const { + return m_pDict->GetByteStringFor("Type"); +} WideString CPDF_StructElement::GetAltText() const { - return GetDict()->GetUnicodeTextFor("Alt"); + return m_pDict->GetUnicodeTextFor("Alt"); +} + +WideString CPDF_StructElement::GetActualText() const { + return m_pDict->GetUnicodeTextFor("ActualText"); } WideString CPDF_StructElement::GetTitle() const { - return GetDict()->GetUnicodeTextFor("T"); + return m_pDict->GetUnicodeTextFor("T"); +} + +absl::optional<WideString> CPDF_StructElement::GetID() const { + RetainPtr<const CPDF_Object> obj = m_pDict->GetObjectFor("ID"); + if (!obj || !obj->IsString()) + return absl::nullopt; + return obj->GetUnicodeText(); +} + +absl::optional<WideString> CPDF_StructElement::GetLang() const { + RetainPtr<const CPDF_Object> obj = m_pDict->GetObjectFor("Lang"); + if (!obj || !obj->IsString()) + return absl::nullopt; + return obj->GetUnicodeText(); +} + +RetainPtr<const CPDF_Object> CPDF_StructElement::GetA() const { + return m_pDict->GetObjectFor("A"); +} + +RetainPtr<const CPDF_Object> CPDF_StructElement::GetK() const { + return m_pDict->GetObjectFor("K"); } size_t CPDF_StructElement::CountKids() const { @@ -63,47 +83,54 @@ } CPDF_StructElement* CPDF_StructElement::GetKidIfElement(size_t index) const { - return m_Kids[index].m_Type == CPDF_StructKid::kElement - ? m_Kids[index].m_pElement.Get() - : nullptr; + return m_Kids[index].m_Type == Kid::kElement ? m_Kids[index].m_pElement.Get() + : nullptr; } -void CPDF_StructElement::LoadKids(const CPDF_Dictionary* pDict) { - const CPDF_Object* pObj = pDict->GetObjectFor("Pg"); - uint32_t PageObjNum = 0; - if (const CPDF_Reference* pRef = ToReference(pObj)) - PageObjNum = pRef->GetRefObjNum(); +bool CPDF_StructElement::UpdateKidIfElement(const CPDF_Dictionary* pDict, + CPDF_StructElement* pElement) { + bool bSave = false; + for (auto& kid : m_Kids) { + if (kid.m_Type == Kid::kElement && kid.m_pDict == pDict) { + kid.m_pElement.Reset(pElement); + bSave = true; + } + } + return bSave; +} - const CPDF_Object* pKids = pDict->GetDirectObjectFor("K"); +void CPDF_StructElement::LoadKids(RetainPtr<const CPDF_Dictionary> pDict) { + RetainPtr<const CPDF_Object> pObj = pDict->GetObjectFor("Pg"); + const CPDF_Reference* pRef = ToReference(pObj.Get()); + const uint32_t PageObjNum = pRef ? pRef->GetRefObjNum() : 0; + RetainPtr<const CPDF_Object> pKids = pDict->GetDirectObjectFor("K"); if (!pKids) return; - m_Kids.clear(); + DCHECK(m_Kids.empty()); if (const CPDF_Array* pArray = pKids->AsArray()) { m_Kids.resize(pArray->size()); - for (uint32_t i = 0; i < pArray->size(); i++) { - const CPDF_Object* pKid = pArray->GetDirectObjectAt(i); - LoadKid(PageObjNum, pKid, &m_Kids[i]); + for (size_t i = 0; i < pArray->size(); ++i) { + LoadKid(PageObjNum, pArray->GetDirectObjectAt(i), &m_Kids[i]); } return; } m_Kids.resize(1); - LoadKid(PageObjNum, pKids, &m_Kids[0]); + LoadKid(PageObjNum, std::move(pKids), &m_Kids[0]); } void CPDF_StructElement::LoadKid(uint32_t PageObjNum, - const CPDF_Object* pKidObj, - CPDF_StructKid* pKid) { - pKid->m_Type = CPDF_StructKid::kInvalid; + RetainPtr<const CPDF_Object> pKidObj, + Kid* pKid) { if (!pKidObj) return; if (pKidObj->IsNumber()) { - if (m_pTree->GetPage()->GetObjNum() != PageObjNum) + if (m_pTree->GetPageObjNum() != PageObjNum) return; - pKid->m_Type = CPDF_StructKid::kPageContent; + pKid->m_Type = Kid::kPageContent; pKid->m_ContentId = pKidObj->GetInteger(); pKid->m_PageObjNum = PageObjNum; return; @@ -112,18 +139,21 @@ const CPDF_Dictionary* pKidDict = pKidObj->AsDictionary(); if (!pKidDict) return; - if (const CPDF_Reference* pRef = ToReference(pKidDict->GetObjectFor("Pg"))) - PageObjNum = pRef->GetRefObjNum(); - ByteString type = pKidDict->GetStringFor("Type"); + if (RetainPtr<const CPDF_Reference> pRef = + ToReference(pKidDict->GetObjectFor("Pg"))) { + PageObjNum = pRef->GetRefObjNum(); + } + ByteString type = pKidDict->GetNameFor("Type"); if ((type == "MCR" || type == "OBJR") && - m_pTree->GetPage()->GetObjNum() != PageObjNum) { + m_pTree->GetPageObjNum() != PageObjNum) { return; } if (type == "MCR") { - pKid->m_Type = CPDF_StructKid::kStreamContent; - const CPDF_Reference* pRef = ToReference(pKidDict->GetObjectFor("Stm")); + pKid->m_Type = Kid::kStreamContent; + RetainPtr<const CPDF_Reference> pRef = + ToReference(pKidDict->GetObjectFor("Stm")); pKid->m_RefObjNum = pRef ? pRef->GetRefObjNum() : 0; pKid->m_PageObjNum = PageObjNum; pKid->m_ContentId = pKidDict->GetIntegerFor("MCID"); @@ -131,14 +161,14 @@ } if (type == "OBJR") { - pKid->m_Type = CPDF_StructKid::kObject; - const CPDF_Reference* pObj = ToReference(pKidDict->GetObjectFor("Obj")); + pKid->m_Type = Kid::kObject; + RetainPtr<const CPDF_Reference> pObj = + ToReference(pKidDict->GetObjectFor("Obj")); pKid->m_RefObjNum = pObj ? pObj->GetRefObjNum() : 0; pKid->m_PageObjNum = PageObjNum; return; } - pKid->m_Type = CPDF_StructKid::kElement; + pKid->m_Type = Kid::kElement; pKid->m_pDict.Reset(pKidDict); - pKid->m_pElement = nullptr; }
diff --git a/core/fpdfdoc/cpdf_structelement.h b/core/fpdfdoc/cpdf_structelement.h index 54042a9..6dd8f8f 100644 --- a/core/fpdfdoc/cpdf_structelement.h +++ b/core/fpdfdoc/cpdf_structelement.h
@@ -1,4 +1,4 @@ -// Copyright 2017 PDFium Authors. All rights reserved. +// Copyright 2017 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -12,60 +12,66 @@ #include "core/fxcrt/fx_string.h" #include "core/fxcrt/retain_ptr.h" #include "core/fxcrt/unowned_ptr.h" +#include "third_party/abseil-cpp/absl/types/optional.h" class CPDF_Dictionary; class CPDF_Object; -class CPDF_StructElement; class CPDF_StructTree; -class CPDF_StructKid { - public: - enum Type { kInvalid, kElement, kPageContent, kStreamContent, kObject }; - - CPDF_StructKid(); - CPDF_StructKid(const CPDF_StructKid& that); - ~CPDF_StructKid(); - - Type m_Type = kInvalid; - uint32_t m_PageObjNum = 0; // For {PageContent, StreamContent, Object} types. - uint32_t m_RefObjNum = 0; // For {StreamContent, Object} types. - uint32_t m_ContentId = 0; // For {PageContent, StreamContent} types. - RetainPtr<CPDF_StructElement> m_pElement; // For Element. - RetainPtr<const CPDF_Dictionary> m_pDict; // For Element. -}; - class CPDF_StructElement final : public Retainable { public: - template <typename T, typename... Args> - friend RetainPtr<T> pdfium::MakeRetain(Args&&... args); + CONSTRUCT_VIA_MAKE_RETAIN; ByteString GetType() const { return m_Type; } + ByteString GetObjType() const; WideString GetAltText() const; + WideString GetActualText() const; WideString GetTitle() const; - - // Never returns nullptr. - const CPDF_Dictionary* GetDict() const { return m_pDict.Get(); } + absl::optional<WideString> GetID() const; + absl::optional<WideString> GetLang() const; + RetainPtr<const CPDF_Object> GetA() const; + RetainPtr<const CPDF_Object> GetK() const; size_t CountKids() const; CPDF_StructElement* GetKidIfElement(size_t index) const; - std::vector<CPDF_StructKid>* GetKids() { return &m_Kids; } + bool UpdateKidIfElement(const CPDF_Dictionary* pDict, + CPDF_StructElement* pElement); + + CPDF_StructElement* GetParent() const { return m_pParentElement; } + void SetParent(CPDF_StructElement* pParentElement) { + m_pParentElement = pParentElement; + } private: - CPDF_StructElement(CPDF_StructTree* pTree, - CPDF_StructElement* pParent, - const CPDF_Dictionary* pDict); + struct Kid { + enum Type { kInvalid, kElement, kPageContent, kStreamContent, kObject }; + + Kid(); + Kid(const Kid& that); + ~Kid(); + + Type m_Type = kInvalid; + uint32_t m_PageObjNum = 0; // For {PageContent, StreamContent, Object}. + uint32_t m_RefObjNum = 0; // For {StreamContent, Object} types. + uint32_t m_ContentId = 0; // For {PageContent, StreamContent} types. + RetainPtr<CPDF_StructElement> m_pElement; // For Element type. + RetainPtr<const CPDF_Dictionary> m_pDict; // For Element type. + }; + + CPDF_StructElement(const CPDF_StructTree* pTree, + RetainPtr<const CPDF_Dictionary> pDict); ~CPDF_StructElement() override; - void LoadKids(const CPDF_Dictionary* pDict); + void LoadKids(RetainPtr<const CPDF_Dictionary> pDict); void LoadKid(uint32_t PageObjNum, - const CPDF_Object* pKidObj, - CPDF_StructKid* pKid); + RetainPtr<const CPDF_Object> pKidObj, + Kid* pKid); - UnownedPtr<CPDF_StructTree> const m_pTree; - UnownedPtr<CPDF_StructElement> const m_pParent; + UnownedPtr<const CPDF_StructTree> const m_pTree; RetainPtr<const CPDF_Dictionary> const m_pDict; + UnownedPtr<CPDF_StructElement> m_pParentElement; const ByteString m_Type; - std::vector<CPDF_StructKid> m_Kids; + std::vector<Kid> m_Kids; }; #endif // CORE_FPDFDOC_CPDF_STRUCTELEMENT_H_
diff --git a/core/fpdfdoc/cpdf_structtree.cpp b/core/fpdfdoc/cpdf_structtree.cpp index 8fd43e2..67ac948 100644 --- a/core/fpdfdoc/cpdf_structtree.cpp +++ b/core/fpdfdoc/cpdf_structtree.cpp
@@ -1,4 +1,4 @@ -// Copyright 2017 PDFium Authors. All rights reserved. +// Copyright 2017 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -6,6 +6,8 @@ #include "core/fpdfdoc/cpdf_structtree.h" +#include <utility> + #include "core/fpdfapi/parser/cpdf_array.h" #include "core/fpdfapi/parser/cpdf_dictionary.h" #include "core/fpdfapi/parser/cpdf_document.h" @@ -13,13 +15,13 @@ #include "core/fpdfapi/parser/cpdf_reference.h" #include "core/fpdfdoc/cpdf_numbertree.h" #include "core/fpdfdoc/cpdf_structelement.h" -#include "third_party/base/ptr_util.h" +#include "core/fxcrt/stl_util.h" namespace { bool IsTagged(const CPDF_Document* pDoc) { - const CPDF_Dictionary* pCatalog = pDoc->GetRoot(); - const CPDF_Dictionary* pMarkInfo = pCatalog->GetDictFor("MarkInfo"); + RetainPtr<const CPDF_Dictionary> pMarkInfo = + pDoc->GetRoot()->GetDictFor("MarkInfo"); return pMarkInfo && pMarkInfo->GetIntegerFor("Marked"); } @@ -28,12 +30,12 @@ // static std::unique_ptr<CPDF_StructTree> CPDF_StructTree::LoadPage( const CPDF_Document* pDoc, - const CPDF_Dictionary* pPageDict) { + RetainPtr<const CPDF_Dictionary> pPageDict) { if (!IsTagged(pDoc)) return nullptr; - auto pTree = pdfium::MakeUnique<CPDF_StructTree>(pDoc); - pTree->LoadPageTree(pPageDict); + auto pTree = std::make_unique<CPDF_StructTree>(pDoc); + pTree->LoadPageTree(std::move(pPageDict)); return pTree; } @@ -43,12 +45,21 @@ CPDF_StructTree::~CPDF_StructTree() = default; -void CPDF_StructTree::LoadPageTree(const CPDF_Dictionary* pPageDict) { - m_pPage.Reset(pPageDict); +ByteString CPDF_StructTree::GetRoleMapNameFor(const ByteString& type) const { + if (m_pRoleMap) { + ByteString mapped = m_pRoleMap->GetNameFor(type); + if (!mapped.IsEmpty()) + return mapped; + } + return type; +} + +void CPDF_StructTree::LoadPageTree(RetainPtr<const CPDF_Dictionary> pPageDict) { + m_pPage = std::move(pPageDict); if (!m_pTreeRoot) return; - const CPDF_Object* pKids = m_pTreeRoot->GetDirectObjectFor("K"); + RetainPtr<const CPDF_Object> pKids = m_pTreeRoot->GetDirectObjectFor("K"); if (!pKids) return; @@ -56,34 +67,38 @@ if (pKids->IsDictionary()) dwKids = 1; else if (const CPDF_Array* pArray = pKids->AsArray()) - dwKids = pArray->size(); + dwKids = fxcrt::CollectionSize<uint32_t>(*pArray); else return; m_Kids.clear(); m_Kids.resize(dwKids); - const CPDF_Dictionary* pParentTree = m_pTreeRoot->GetDictFor("ParentTree"); + + RetainPtr<const CPDF_Dictionary> pParentTree = + m_pTreeRoot->GetDictFor("ParentTree"); if (!pParentTree) return; - CPDF_NumberTree parent_tree(pParentTree); - int parents_id = pPageDict->GetIntegerFor("StructParents", -1); + CPDF_NumberTree parent_tree(std::move(pParentTree)); + int parents_id = m_pPage->GetIntegerFor("StructParents", -1); if (parents_id < 0) return; - const CPDF_Array* pParentArray = ToArray(parent_tree.LookupValue(parents_id)); + RetainPtr<const CPDF_Array> pParentArray = + ToArray(parent_tree.LookupValue(parents_id)); if (!pParentArray) return; StructElementMap element_map; for (size_t i = 0; i < pParentArray->size(); i++) { - if (const CPDF_Dictionary* pParent = pParentArray->GetDictAt(i)) - AddPageNode(pParent, &element_map, 0); + RetainPtr<const CPDF_Dictionary> pParent = pParentArray->GetDictAt(i); + if (pParent) + AddPageNode(std::move(pParent), &element_map, 0); } } RetainPtr<CPDF_StructElement> CPDF_StructTree::AddPageNode( - const CPDF_Dictionary* pDict, + RetainPtr<const CPDF_Dictionary> pDict, StructElementMap* map, int nLevel) { static constexpr int kStructTreeMaxRecursion = 32; @@ -94,33 +109,33 @@ if (it != map->end()) return it->second; - auto pElement = pdfium::MakeRetain<CPDF_StructElement>(this, nullptr, pDict); - (*map)[pDict] = pElement; - const CPDF_Dictionary* pParent = pDict->GetDictFor("P"); - if (!pParent || pParent->GetStringFor("Type") == "StructTreeRoot") { + RetainPtr<const CPDF_Dictionary> key(pDict); + auto pElement = pdfium::MakeRetain<CPDF_StructElement>(this, pDict); + (*map)[key] = pElement; + RetainPtr<const CPDF_Dictionary> pParent = pDict->GetDictFor("P"); + if (!pParent || pParent->GetNameFor("Type") == "StructTreeRoot") { if (!AddTopLevelNode(pDict, pElement)) - map->erase(pDict); + map->erase(key); return pElement; } RetainPtr<CPDF_StructElement> pParentElement = - AddPageNode(pParent, map, nLevel + 1); - bool bSave = false; - for (CPDF_StructKid& kid : *pParentElement->GetKids()) { - if (kid.m_Type == CPDF_StructKid::kElement && kid.m_pDict == pDict) { - kid.m_pElement = pElement; - bSave = true; - } - } - if (!bSave) - map->erase(pDict); + AddPageNode(std::move(pParent), map, nLevel + 1); + if (!pParentElement) + return pElement; + + if (!pParentElement->UpdateKidIfElement(pDict, pElement.Get())) + map->erase(key); + + pElement->SetParent(pParentElement.Get()); + return pElement; } bool CPDF_StructTree::AddTopLevelNode( const CPDF_Dictionary* pDict, const RetainPtr<CPDF_StructElement>& pElement) { - const CPDF_Object* pObj = m_pTreeRoot->GetDirectObjectFor("K"); + RetainPtr<const CPDF_Object> pObj = m_pTreeRoot->GetDirectObjectFor("K"); if (!pObj) return false; @@ -136,7 +151,8 @@ bool bSave = false; for (size_t i = 0; i < pTopKids->size(); i++) { - const CPDF_Reference* pKidRef = ToReference(pTopKids->GetObjectAt(i)); + RetainPtr<const CPDF_Reference> pKidRef = + ToReference(pTopKids->GetObjectAt(i)); if (pKidRef && pKidRef->GetRefObjNum() == pDict->GetObjNum()) { m_Kids[i] = pElement; bSave = true;
diff --git a/core/fpdfdoc/cpdf_structtree.h b/core/fpdfdoc/cpdf_structtree.h index b0eafba..8cca8b2 100644 --- a/core/fpdfdoc/cpdf_structtree.h +++ b/core/fpdfdoc/cpdf_structtree.h
@@ -1,4 +1,4 @@ -// Copyright 2017 PDFium Authors. All rights reserved. +// Copyright 2017 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -7,13 +7,15 @@ #ifndef CORE_FPDFDOC_CPDF_STRUCTTREE_H_ #define CORE_FPDFDOC_CPDF_STRUCTTREE_H_ +#include <functional> #include <map> #include <memory> #include <vector> +#include "core/fpdfapi/parser/cpdf_dictionary.h" +#include "core/fxcrt/bytestring.h" #include "core/fxcrt/retain_ptr.h" -class CPDF_Dictionary; class CPDF_Document; class CPDF_StructElement; @@ -21,25 +23,26 @@ public: static std::unique_ptr<CPDF_StructTree> LoadPage( const CPDF_Document* pDoc, - const CPDF_Dictionary* pPageDict); + RetainPtr<const CPDF_Dictionary> pPageDict); explicit CPDF_StructTree(const CPDF_Document* pDoc); ~CPDF_StructTree(); size_t CountTopElements() const { return m_Kids.size(); } CPDF_StructElement* GetTopElement(size_t i) const { return m_Kids[i].Get(); } - const CPDF_Dictionary* GetRoleMap() const { return m_pRoleMap.Get(); } - const CPDF_Dictionary* GetPage() const { return m_pPage.Get(); } - const CPDF_Dictionary* GetTreeRoot() const { return m_pTreeRoot.Get(); } + uint32_t GetPageObjNum() const { return m_pPage->GetObjNum(); } + ByteString GetRoleMapNameFor(const ByteString& type) const; private: - using StructElementMap = - std::map<const CPDF_Dictionary*, RetainPtr<CPDF_StructElement>>; + using StructElementMap = std::map<RetainPtr<const CPDF_Dictionary>, + RetainPtr<CPDF_StructElement>, + std::less<>>; - void LoadPageTree(const CPDF_Dictionary* pPageDict); - RetainPtr<CPDF_StructElement> AddPageNode(const CPDF_Dictionary* pDict, - StructElementMap* map, - int nLevel); + void LoadPageTree(RetainPtr<const CPDF_Dictionary> pPageDict); + RetainPtr<CPDF_StructElement> AddPageNode( + RetainPtr<const CPDF_Dictionary> pDict, + StructElementMap* map, + int nLevel); bool AddTopLevelNode(const CPDF_Dictionary* pDict, const RetainPtr<CPDF_StructElement>& pElement);
diff --git a/core/fpdfdoc/cpdf_variabletext.cpp b/core/fpdfdoc/cpdf_variabletext.cpp deleted file mode 100644 index d7d2265..0000000 --- a/core/fpdfdoc/cpdf_variabletext.cpp +++ /dev/null
@@ -1,937 +0,0 @@ -// Copyright 2016 PDFium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com - -#include "core/fpdfdoc/cpdf_variabletext.h" - -#include <algorithm> -#include <utility> - -#include "core/fpdfapi/font/cpdf_font.h" -#include "core/fpdfdoc/cline.h" -#include "core/fpdfdoc/cpvt_word.h" -#include "core/fpdfdoc/cpvt_wordinfo.h" -#include "core/fpdfdoc/csection.h" -#include "core/fpdfdoc/ipvt_fontmap.h" -#include "core/fxcrt/fx_codepage.h" -#include "third_party/base/compiler_specific.h" -#include "third_party/base/ptr_util.h" -#include "third_party/base/stl_util.h" - -namespace { - -const float kFontScale = 0.001f; -const uint8_t kReturnLength = 1; - -const uint8_t gFontSizeSteps[] = {4, 6, 8, 9, 10, 12, 14, 18, 20, - 25, 30, 35, 40, 45, 50, 55, 60, 70, - 80, 90, 100, 110, 120, 130, 144}; - -} // namespace - -CPDF_VariableText::Provider::Provider(IPVT_FontMap* pFontMap) - : m_pFontMap(pFontMap) { - ASSERT(m_pFontMap); -} - -CPDF_VariableText::Provider::~Provider() {} - -uint32_t CPDF_VariableText::Provider::GetCharWidth(int32_t nFontIndex, - uint16_t word) { - RetainPtr<CPDF_Font> pPDFFont = m_pFontMap->GetPDFFont(nFontIndex); - if (!pPDFFont) - return 0; - - uint32_t charcode = pPDFFont->CharCodeFromUnicode(word); - if (charcode == CPDF_Font::kInvalidCharCode) - return 0; - - return pPDFFont->GetCharWidthF(charcode); -} - -int32_t CPDF_VariableText::Provider::GetTypeAscent(int32_t nFontIndex) { - RetainPtr<CPDF_Font> pPDFFont = m_pFontMap->GetPDFFont(nFontIndex); - return pPDFFont ? pPDFFont->GetTypeAscent() : 0; -} - -int32_t CPDF_VariableText::Provider::GetTypeDescent(int32_t nFontIndex) { - RetainPtr<CPDF_Font> pPDFFont = m_pFontMap->GetPDFFont(nFontIndex); - return pPDFFont ? pPDFFont->GetTypeDescent() : 0; -} - -int32_t CPDF_VariableText::Provider::GetWordFontIndex(uint16_t word, - int32_t charset, - int32_t nFontIndex) { - if (RetainPtr<CPDF_Font> pDefFont = m_pFontMap->GetPDFFont(0)) { - if (pDefFont->CharCodeFromUnicode(word) != CPDF_Font::kInvalidCharCode) - return 0; - } - if (RetainPtr<CPDF_Font> pSysFont = m_pFontMap->GetPDFFont(1)) { - if (pSysFont->CharCodeFromUnicode(word) != CPDF_Font::kInvalidCharCode) - return 1; - } - return -1; -} - -bool CPDF_VariableText::Provider::IsLatinWord(uint16_t word) { - return (word >= 0x61 && word <= 0x7A) || (word >= 0x41 && word <= 0x5A) || - word == 0x2D || word == 0x27; -} - -int32_t CPDF_VariableText::Provider::GetDefaultFontIndex() { - return 0; -} - -CPDF_VariableText::Iterator::Iterator(CPDF_VariableText* pVT) - : m_CurPos(-1, -1, -1), m_pVT(pVT) {} - -CPDF_VariableText::Iterator::~Iterator() {} - -void CPDF_VariableText::Iterator::SetAt(int32_t nWordIndex) { - m_CurPos = m_pVT->WordIndexToWordPlace(nWordIndex); -} - -void CPDF_VariableText::Iterator::SetAt(const CPVT_WordPlace& place) { - ASSERT(m_pVT); - m_CurPos = place; -} - -bool CPDF_VariableText::Iterator::NextWord() { - if (m_CurPos == m_pVT->GetEndWordPlace()) - return false; - - m_CurPos = m_pVT->GetNextWordPlace(m_CurPos); - return true; -} - -bool CPDF_VariableText::Iterator::PrevWord() { - if (m_CurPos == m_pVT->GetBeginWordPlace()) - return false; - - m_CurPos = m_pVT->GetPrevWordPlace(m_CurPos); - return true; -} - -bool CPDF_VariableText::Iterator::NextLine() { - if (!pdfium::IndexInBounds(m_pVT->m_SectionArray, m_CurPos.nSecIndex)) - return false; - - CSection* pSection = m_pVT->m_SectionArray[m_CurPos.nSecIndex].get(); - if (m_CurPos.nLineIndex < - pdfium::CollectionSize<int32_t>(pSection->m_LineArray) - 1) { - m_CurPos = CPVT_WordPlace(m_CurPos.nSecIndex, m_CurPos.nLineIndex + 1, -1); - return true; - } - if (m_CurPos.nSecIndex < - pdfium::CollectionSize<int32_t>(m_pVT->m_SectionArray) - 1) { - m_CurPos = CPVT_WordPlace(m_CurPos.nSecIndex + 1, 0, -1); - return true; - } - return false; -} - -bool CPDF_VariableText::Iterator::GetWord(CPVT_Word& word) const { - word.WordPlace = m_CurPos; - if (!pdfium::IndexInBounds(m_pVT->m_SectionArray, m_CurPos.nSecIndex)) - return false; - - CSection* pSection = m_pVT->m_SectionArray[m_CurPos.nSecIndex].get(); - if (!pdfium::IndexInBounds(pSection->m_LineArray, m_CurPos.nLineIndex) || - !pdfium::IndexInBounds(pSection->m_WordArray, m_CurPos.nWordIndex)) { - return false; - } - - CPVT_WordInfo* pWord = pSection->m_WordArray[m_CurPos.nWordIndex].get(); - word.Word = pWord->Word; - word.nCharset = pWord->nCharset; - word.fWidth = m_pVT->GetWordWidth(*pWord); - word.ptWord = - m_pVT->InToOut(CFX_PointF(pWord->fWordX + pSection->m_Rect.left, - pWord->fWordY + pSection->m_Rect.top)); - word.fAscent = m_pVT->GetWordAscent(*pWord); - word.fDescent = m_pVT->GetWordDescent(*pWord); - word.nFontIndex = m_pVT->GetWordFontIndex(*pWord); - word.fFontSize = m_pVT->GetWordFontSize(); - return true; -} - -bool CPDF_VariableText::Iterator::GetLine(CPVT_Line& line) const { - ASSERT(m_pVT); - line.lineplace = CPVT_WordPlace(m_CurPos.nSecIndex, m_CurPos.nLineIndex, -1); - if (!pdfium::IndexInBounds(m_pVT->m_SectionArray, m_CurPos.nSecIndex)) - return false; - - CSection* pSection = m_pVT->m_SectionArray[m_CurPos.nSecIndex].get(); - if (!pdfium::IndexInBounds(pSection->m_LineArray, m_CurPos.nLineIndex)) - return false; - - CLine* pLine = pSection->m_LineArray[m_CurPos.nLineIndex].get(); - line.ptLine = m_pVT->InToOut( - CFX_PointF(pLine->m_LineInfo.fLineX + pSection->m_Rect.left, - pLine->m_LineInfo.fLineY + pSection->m_Rect.top)); - line.fLineWidth = pLine->m_LineInfo.fLineWidth; - line.fLineAscent = pLine->m_LineInfo.fLineAscent; - line.fLineDescent = pLine->m_LineInfo.fLineDescent; - line.lineEnd = pLine->GetEndWordPlace(); - return true; -} - -CPDF_VariableText::CPDF_VariableText() = default; - -CPDF_VariableText::~CPDF_VariableText() = default; - -void CPDF_VariableText::Initialize() { - if (m_bInitialized) - return; - - CPVT_WordPlace place; - place.nSecIndex = 0; - AddSection(place); - - CPVT_LineInfo lineinfo; - lineinfo.fLineAscent = GetFontAscent(GetDefaultFontIndex(), GetFontSize()); - lineinfo.fLineDescent = GetFontDescent(GetDefaultFontIndex(), GetFontSize()); - AddLine(place, lineinfo); - - if (!m_SectionArray.empty()) - m_SectionArray.front()->ResetLinePlace(); - - m_bInitialized = true; -} - -CPVT_WordPlace CPDF_VariableText::InsertWord(const CPVT_WordPlace& place, - uint16_t word, - int32_t charset) { - int32_t nTotalWords = GetTotalWords(); - if (m_nLimitChar > 0 && nTotalWords >= m_nLimitChar) - return place; - if (m_nCharArray > 0 && nTotalWords >= m_nCharArray) - return place; - - CPVT_WordPlace newplace = place; - newplace.nWordIndex++; - int32_t nFontIndex = - GetSubWord() > 0 ? GetDefaultFontIndex() - : GetWordFontIndex(word, charset, GetDefaultFontIndex()); - return AddWord(newplace, CPVT_WordInfo(word, charset, nFontIndex)); -} - -CPVT_WordPlace CPDF_VariableText::InsertSection(const CPVT_WordPlace& place) { - int32_t nTotalWords = GetTotalWords(); - if (m_nLimitChar > 0 && nTotalWords >= m_nLimitChar) - return place; - if (m_nCharArray > 0 && nTotalWords >= m_nCharArray) - return place; - if (!m_bMultiLine) - return place; - - CPVT_WordPlace wordplace = place; - UpdateWordPlace(wordplace); - if (!pdfium::IndexInBounds(m_SectionArray, wordplace.nSecIndex)) - return place; - - CSection* pSection = m_SectionArray[wordplace.nSecIndex].get(); - CPVT_WordPlace NewPlace(wordplace.nSecIndex + 1, 0, -1); - AddSection(NewPlace); - CPVT_WordPlace result = NewPlace; - if (pdfium::IndexInBounds(m_SectionArray, NewPlace.nSecIndex)) { - CSection* pNewSection = m_SectionArray[NewPlace.nSecIndex].get(); - for (int32_t w = wordplace.nWordIndex + 1; - w < pdfium::CollectionSize<int32_t>(pSection->m_WordArray); ++w) { - NewPlace.nWordIndex++; - pNewSection->AddWord(NewPlace, *pSection->m_WordArray[w]); - } - } - ClearSectionRightWords(wordplace); - return result; -} - -CPVT_WordPlace CPDF_VariableText::DeleteWords( - const CPVT_WordRange& PlaceRange) { - bool bLastSecPos = - pdfium::IndexInBounds(m_SectionArray, PlaceRange.EndPos.nSecIndex) && - PlaceRange.EndPos == - m_SectionArray[PlaceRange.EndPos.nSecIndex]->GetEndWordPlace(); - - ClearWords(PlaceRange); - if (PlaceRange.BeginPos.nSecIndex != PlaceRange.EndPos.nSecIndex) { - ClearEmptySections(PlaceRange); - if (!bLastSecPos) - LinkLatterSection(PlaceRange.BeginPos); - } - return PlaceRange.BeginPos; -} - -CPVT_WordPlace CPDF_VariableText::DeleteWord(const CPVT_WordPlace& place) { - return ClearRightWord(AdjustLineHeader(place, true)); -} - -CPVT_WordPlace CPDF_VariableText::BackSpaceWord(const CPVT_WordPlace& place) { - return ClearLeftWord(AdjustLineHeader(place, true)); -} - -void CPDF_VariableText::SetText(const WideString& swText) { - DeleteWords(CPVT_WordRange(GetBeginWordPlace(), GetEndWordPlace())); - CPVT_WordPlace wp(0, 0, -1); - if (!m_SectionArray.empty()) - m_SectionArray.front()->m_Rect = CPVT_FloatRect(); - - int32_t nCharCount = 0; - for (int32_t i = 0, sz = swText.GetLength(); i < sz; i++) { - if (m_nLimitChar > 0 && nCharCount >= m_nLimitChar) - break; - if (m_nCharArray > 0 && nCharCount >= m_nCharArray) - break; - - uint16_t word = swText[i]; - switch (word) { - case 0x0D: - if (m_bMultiLine) { - if (i + 1 < sz && swText[i + 1] == 0x0A) - i++; - wp.AdvanceSection(); - AddSection(wp); - } - break; - case 0x0A: - if (m_bMultiLine) { - if (i + 1 < sz && swText[i + 1] == 0x0D) - i++; - wp.AdvanceSection(); - AddSection(wp); - } - break; - case 0x09: - word = 0x20; - FALLTHROUGH; - default: - wp = InsertWord(wp, word, FX_CHARSET_Default); - break; - } - nCharCount++; - } -} - -void CPDF_VariableText::UpdateWordPlace(CPVT_WordPlace& place) const { - if (place.nSecIndex < 0) - place = GetBeginWordPlace(); - if (place.nSecIndex >= pdfium::CollectionSize<int32_t>(m_SectionArray)) - place = GetEndWordPlace(); - - place = AdjustLineHeader(place, true); - if (pdfium::IndexInBounds(m_SectionArray, place.nSecIndex)) - m_SectionArray[place.nSecIndex]->UpdateWordPlace(place); -} - -int32_t CPDF_VariableText::WordPlaceToWordIndex( - const CPVT_WordPlace& place) const { - CPVT_WordPlace newplace = place; - UpdateWordPlace(newplace); - int32_t nIndex = 0; - int32_t i = 0; - int32_t sz = 0; - for (i = 0, sz = pdfium::CollectionSize<int32_t>(m_SectionArray); - i < sz && i < newplace.nSecIndex; i++) { - CSection* pSection = m_SectionArray[i].get(); - nIndex += pdfium::CollectionSize<int32_t>(pSection->m_WordArray); - if (i != sz - 1) - nIndex += kReturnLength; - } - if (pdfium::IndexInBounds(m_SectionArray, i)) - nIndex += newplace.nWordIndex + kReturnLength; - return nIndex; -} - -CPVT_WordPlace CPDF_VariableText::WordIndexToWordPlace(int32_t index) const { - CPVT_WordPlace place = GetBeginWordPlace(); - int32_t nOldIndex = 0; - int32_t nIndex = 0; - bool bFound = false; - for (int32_t i = 0, sz = pdfium::CollectionSize<int32_t>(m_SectionArray); - i < sz; i++) { - CSection* pSection = m_SectionArray[i].get(); - nIndex += pdfium::CollectionSize<int32_t>(pSection->m_WordArray); - if (nIndex == index) { - place = pSection->GetEndWordPlace(); - bFound = true; - break; - } - if (nIndex > index) { - place.nSecIndex = i; - place.nWordIndex = index - nOldIndex - 1; - pSection->UpdateWordPlace(place); - bFound = true; - break; - } - if (i != sz - 1) - nIndex += kReturnLength; - nOldIndex = nIndex; - } - if (!bFound) - place = GetEndWordPlace(); - return place; -} - -CPVT_WordPlace CPDF_VariableText::GetBeginWordPlace() const { - return m_bInitialized ? CPVT_WordPlace(0, 0, -1) : CPVT_WordPlace(); -} - -CPVT_WordPlace CPDF_VariableText::GetEndWordPlace() const { - if (m_SectionArray.empty()) - return CPVT_WordPlace(); - return m_SectionArray.back()->GetEndWordPlace(); -} - -CPVT_WordPlace CPDF_VariableText::GetPrevWordPlace( - const CPVT_WordPlace& place) const { - if (place.nSecIndex < 0) - return GetBeginWordPlace(); - if (place.nSecIndex >= pdfium::CollectionSize<int32_t>(m_SectionArray)) - return GetEndWordPlace(); - - CSection* pSection = m_SectionArray[place.nSecIndex].get(); - if (place > pSection->GetBeginWordPlace()) - return pSection->GetPrevWordPlace(place); - if (!pdfium::IndexInBounds(m_SectionArray, place.nSecIndex - 1)) - return GetBeginWordPlace(); - return m_SectionArray[place.nSecIndex - 1]->GetEndWordPlace(); -} - -CPVT_WordPlace CPDF_VariableText::GetNextWordPlace( - const CPVT_WordPlace& place) const { - if (place.nSecIndex < 0) - return GetBeginWordPlace(); - if (place.nSecIndex >= pdfium::CollectionSize<int32_t>(m_SectionArray)) - return GetEndWordPlace(); - - CSection* pSection = m_SectionArray[place.nSecIndex].get(); - if (place < pSection->GetEndWordPlace()) - return pSection->GetNextWordPlace(place); - if (!pdfium::IndexInBounds(m_SectionArray, place.nSecIndex + 1)) - return GetEndWordPlace(); - return m_SectionArray[place.nSecIndex + 1]->GetBeginWordPlace(); -} - -CPVT_WordPlace CPDF_VariableText::SearchWordPlace( - const CFX_PointF& point) const { - CFX_PointF pt = OutToIn(point); - CPVT_WordPlace place = GetBeginWordPlace(); - int32_t nLeft = 0; - int32_t nRight = pdfium::CollectionSize<int32_t>(m_SectionArray) - 1; - int32_t nMid = pdfium::CollectionSize<int32_t>(m_SectionArray) / 2; - bool bUp = true; - bool bDown = true; - while (nLeft <= nRight) { - if (!pdfium::IndexInBounds(m_SectionArray, nMid)) - break; - CSection* pSection = m_SectionArray[nMid].get(); - if (IsFloatBigger(pt.y, pSection->m_Rect.top)) - bUp = false; - if (IsFloatBigger(pSection->m_Rect.bottom, pt.y)) - bDown = false; - if (IsFloatSmaller(pt.y, pSection->m_Rect.top)) { - nRight = nMid - 1; - nMid = (nLeft + nRight) / 2; - continue; - } - if (IsFloatBigger(pt.y, pSection->m_Rect.bottom)) { - nLeft = nMid + 1; - nMid = (nLeft + nRight) / 2; - continue; - } - place = pSection->SearchWordPlace( - CFX_PointF(pt.x - pSection->m_Rect.left, pt.y - pSection->m_Rect.top)); - place.nSecIndex = nMid; - return place; - } - if (bUp) - place = GetBeginWordPlace(); - if (bDown) - place = GetEndWordPlace(); - return place; -} - -CPVT_WordPlace CPDF_VariableText::GetUpWordPlace( - const CPVT_WordPlace& place, - const CFX_PointF& point) const { - if (!pdfium::IndexInBounds(m_SectionArray, place.nSecIndex)) - return place; - - CSection* pSection = m_SectionArray[place.nSecIndex].get(); - CPVT_WordPlace temp = place; - CFX_PointF pt = OutToIn(point); - if (temp.nLineIndex-- > 0) { - return pSection->SearchWordPlace(pt.x - pSection->m_Rect.left, temp); - } - if (temp.nSecIndex-- > 0) { - if (pdfium::IndexInBounds(m_SectionArray, temp.nSecIndex)) { - CSection* pLastSection = m_SectionArray[temp.nSecIndex].get(); - temp.nLineIndex = - pdfium::CollectionSize<int32_t>(pLastSection->m_LineArray) - 1; - return pLastSection->SearchWordPlace(pt.x - pLastSection->m_Rect.left, - temp); - } - } - return place; -} - -CPVT_WordPlace CPDF_VariableText::GetDownWordPlace( - const CPVT_WordPlace& place, - const CFX_PointF& point) const { - if (!pdfium::IndexInBounds(m_SectionArray, place.nSecIndex)) - return place; - - CSection* pSection = m_SectionArray[place.nSecIndex].get(); - CPVT_WordPlace temp = place; - CFX_PointF pt = OutToIn(point); - if (temp.nLineIndex++ < - pdfium::CollectionSize<int32_t>(pSection->m_LineArray) - 1) { - return pSection->SearchWordPlace(pt.x - pSection->m_Rect.left, temp); - } - temp.AdvanceSection(); - if (!pdfium::IndexInBounds(m_SectionArray, temp.nSecIndex)) - return place; - - return m_SectionArray[temp.nSecIndex]->SearchWordPlace( - pt.x - pSection->m_Rect.left, temp); -} - -CPVT_WordPlace CPDF_VariableText::GetLineBeginPlace( - const CPVT_WordPlace& place) const { - return CPVT_WordPlace(place.nSecIndex, place.nLineIndex, -1); -} - -CPVT_WordPlace CPDF_VariableText::GetLineEndPlace( - const CPVT_WordPlace& place) const { - if (!pdfium::IndexInBounds(m_SectionArray, place.nSecIndex)) - return place; - - CSection* pSection = m_SectionArray[place.nSecIndex].get(); - if (!pdfium::IndexInBounds(pSection->m_LineArray, place.nLineIndex)) - return place; - - return pSection->m_LineArray[place.nLineIndex]->GetEndWordPlace(); -} - -CPVT_WordPlace CPDF_VariableText::GetSectionBeginPlace( - const CPVT_WordPlace& place) const { - return CPVT_WordPlace(place.nSecIndex, 0, -1); -} - -CPVT_WordPlace CPDF_VariableText::GetSectionEndPlace( - const CPVT_WordPlace& place) const { - if (!pdfium::IndexInBounds(m_SectionArray, place.nSecIndex)) - return place; - - return m_SectionArray[place.nSecIndex]->GetEndWordPlace(); -} - -int32_t CPDF_VariableText::GetTotalWords() const { - int32_t nTotal = 0; - for (const auto& pSection : m_SectionArray) { - nTotal += - pdfium::CollectionSize<int32_t>(pSection->m_WordArray) + kReturnLength; - } - return nTotal - kReturnLength; -} - -CPVT_WordPlace CPDF_VariableText::AddSection(const CPVT_WordPlace& place) { - if (IsValid() && !m_bMultiLine) - return place; - - int32_t nSecIndex = pdfium::clamp( - place.nSecIndex, 0, pdfium::CollectionSize<int32_t>(m_SectionArray)); - - auto pSection = pdfium::MakeUnique<CSection>(this); - pSection->m_Rect = CPVT_FloatRect(); - pSection->SecPlace.nSecIndex = nSecIndex; - m_SectionArray.insert(m_SectionArray.begin() + nSecIndex, - std::move(pSection)); - return place; -} - -CPVT_WordPlace CPDF_VariableText::AddLine(const CPVT_WordPlace& place, - const CPVT_LineInfo& lineinfo) { - if (!pdfium::IndexInBounds(m_SectionArray, place.nSecIndex)) - return place; - - return m_SectionArray[place.nSecIndex]->AddLine(lineinfo); -} - -CPVT_WordPlace CPDF_VariableText::AddWord(const CPVT_WordPlace& place, - const CPVT_WordInfo& wordinfo) { - if (m_SectionArray.empty()) - return place; - - CPVT_WordPlace newplace = place; - newplace.nSecIndex = - pdfium::clamp(newplace.nSecIndex, 0, - pdfium::CollectionSize<int32_t>(m_SectionArray) - 1); - return m_SectionArray[newplace.nSecIndex]->AddWord(newplace, wordinfo); -} - -void CPDF_VariableText::SetPlateRect(const CFX_FloatRect& rect) { - m_rcPlate = rect; -} - -void CPDF_VariableText::SetContentRect(const CPVT_FloatRect& rect) { - m_rcContent = rect; -} - -CFX_FloatRect CPDF_VariableText::GetContentRect() const { - return InToOut(CPVT_FloatRect(m_rcContent)); -} - -const CFX_FloatRect& CPDF_VariableText::GetPlateRect() const { - return m_rcPlate; -} - -float CPDF_VariableText::GetWordFontSize() { - return GetFontSize(); -} - -int32_t CPDF_VariableText::GetWordFontIndex(const CPVT_WordInfo& WordInfo) { - return WordInfo.nFontIndex; -} - -float CPDF_VariableText::GetWordWidth(int32_t nFontIndex, - uint16_t Word, - uint16_t SubWord, - float fCharSpace, - float fFontSize, - float fWordTail) { - return GetCharWidth(nFontIndex, Word, SubWord) * fFontSize * kFontScale + - fCharSpace + fWordTail; -} - -float CPDF_VariableText::GetWordWidth(const CPVT_WordInfo& WordInfo) { - return GetWordWidth(GetWordFontIndex(WordInfo), WordInfo.Word, GetSubWord(), - GetCharSpace(), GetWordFontSize(), WordInfo.fWordTail); -} - -float CPDF_VariableText::GetLineAscent() { - return GetFontAscent(GetDefaultFontIndex(), GetFontSize()); -} - -float CPDF_VariableText::GetLineDescent() { - return GetFontDescent(GetDefaultFontIndex(), GetFontSize()); -} - -float CPDF_VariableText::GetFontAscent(int32_t nFontIndex, float fFontSize) { - return (float)GetTypeAscent(nFontIndex) * fFontSize * kFontScale; -} - -float CPDF_VariableText::GetFontDescent(int32_t nFontIndex, float fFontSize) { - return (float)GetTypeDescent(nFontIndex) * fFontSize * kFontScale; -} - -float CPDF_VariableText::GetWordAscent(const CPVT_WordInfo& WordInfo, - float fFontSize) { - return GetFontAscent(GetWordFontIndex(WordInfo), fFontSize); -} - -float CPDF_VariableText::GetWordDescent(const CPVT_WordInfo& WordInfo, - float fFontSize) { - return GetFontDescent(GetWordFontIndex(WordInfo), fFontSize); -} - -float CPDF_VariableText::GetWordAscent(const CPVT_WordInfo& WordInfo) { - return GetFontAscent(GetWordFontIndex(WordInfo), GetWordFontSize()); -} - -float CPDF_VariableText::GetWordDescent(const CPVT_WordInfo& WordInfo) { - return GetFontDescent(GetWordFontIndex(WordInfo), GetWordFontSize()); -} - -float CPDF_VariableText::GetLineLeading() { - return m_fLineLeading; -} - -float CPDF_VariableText::GetLineIndent() { - return 0.0f; -} - -int32_t CPDF_VariableText::GetAlignment() { - return m_nAlignment; -} - -void CPDF_VariableText::ClearSectionRightWords(const CPVT_WordPlace& place) { - CPVT_WordPlace wordplace = AdjustLineHeader(place, true); - if (!pdfium::IndexInBounds(m_SectionArray, place.nSecIndex)) - return; - - CSection* pSection = m_SectionArray[place.nSecIndex].get(); - if (!pdfium::IndexInBounds(pSection->m_WordArray, wordplace.nWordIndex + 1)) - return; - - pSection->m_WordArray.erase( - pSection->m_WordArray.begin() + wordplace.nWordIndex + 1, - pSection->m_WordArray.end()); -} - -CPVT_WordPlace CPDF_VariableText::AdjustLineHeader(const CPVT_WordPlace& place, - bool bPrevOrNext) const { - if (place.nWordIndex < 0 && place.nLineIndex > 0) - return bPrevOrNext ? GetPrevWordPlace(place) : GetNextWordPlace(place); - return place; -} - -bool CPDF_VariableText::ClearEmptySection(const CPVT_WordPlace& place) { - if (place.nSecIndex == 0 && m_SectionArray.size() == 1) - return false; - - if (!pdfium::IndexInBounds(m_SectionArray, place.nSecIndex)) - return false; - - if (!m_SectionArray[place.nSecIndex]->m_WordArray.empty()) - return false; - - m_SectionArray.erase(m_SectionArray.begin() + place.nSecIndex); - return true; -} - -void CPDF_VariableText::ClearEmptySections(const CPVT_WordRange& PlaceRange) { - CPVT_WordPlace wordplace; - for (int32_t s = PlaceRange.EndPos.nSecIndex; - s > PlaceRange.BeginPos.nSecIndex; s--) { - wordplace.nSecIndex = s; - ClearEmptySection(wordplace); - } -} - -void CPDF_VariableText::LinkLatterSection(const CPVT_WordPlace& place) { - CPVT_WordPlace oldplace = AdjustLineHeader(place, true); - if (!pdfium::IndexInBounds(m_SectionArray, place.nSecIndex + 1)) - return; - - CSection* pNextSection = m_SectionArray[place.nSecIndex + 1].get(); - if (pdfium::IndexInBounds(m_SectionArray, oldplace.nSecIndex)) { - CSection* pSection = m_SectionArray[oldplace.nSecIndex].get(); - for (auto& pWord : pNextSection->m_WordArray) { - oldplace.nWordIndex++; - pSection->AddWord(oldplace, *pWord); - } - } - m_SectionArray.erase(m_SectionArray.begin() + place.nSecIndex + 1); -} - -void CPDF_VariableText::ClearWords(const CPVT_WordRange& PlaceRange) { - CPVT_WordRange NewRange; - NewRange.BeginPos = AdjustLineHeader(PlaceRange.BeginPos, true); - NewRange.EndPos = AdjustLineHeader(PlaceRange.EndPos, true); - for (int32_t s = NewRange.EndPos.nSecIndex; s >= NewRange.BeginPos.nSecIndex; - s--) { - if (pdfium::IndexInBounds(m_SectionArray, s)) - m_SectionArray[s]->ClearWords(NewRange); - } -} - -CPVT_WordPlace CPDF_VariableText::ClearLeftWord(const CPVT_WordPlace& place) { - if (!pdfium::IndexInBounds(m_SectionArray, place.nSecIndex)) - return place; - - CSection* pSection = m_SectionArray[place.nSecIndex].get(); - CPVT_WordPlace leftplace = GetPrevWordPlace(place); - if (leftplace == place) - return place; - - if (leftplace.nSecIndex != place.nSecIndex) { - if (pSection->m_WordArray.empty()) - ClearEmptySection(place); - else - LinkLatterSection(leftplace); - } else { - pSection->ClearWord(place); - } - return leftplace; -} - -CPVT_WordPlace CPDF_VariableText::ClearRightWord(const CPVT_WordPlace& place) { - if (!pdfium::IndexInBounds(m_SectionArray, place.nSecIndex)) - return place; - - CSection* pSection = m_SectionArray[place.nSecIndex].get(); - CPVT_WordPlace rightplace = AdjustLineHeader(GetNextWordPlace(place), false); - if (rightplace == place) - return place; - - if (rightplace.nSecIndex != place.nSecIndex) - LinkLatterSection(place); - else - pSection->ClearWord(rightplace); - return place; -} - -void CPDF_VariableText::RearrangeAll() { - Rearrange(CPVT_WordRange(GetBeginWordPlace(), GetEndWordPlace())); -} - -void CPDF_VariableText::RearrangePart(const CPVT_WordRange& PlaceRange) { - Rearrange(PlaceRange); -} - -CPVT_FloatRect CPDF_VariableText::Rearrange(const CPVT_WordRange& PlaceRange) { - CPVT_FloatRect rcRet; - if (IsValid()) { - if (m_bAutoFontSize) { - SetFontSize(GetAutoFontSize()); - rcRet = RearrangeSections( - CPVT_WordRange(GetBeginWordPlace(), GetEndWordPlace())); - } else { - rcRet = RearrangeSections(PlaceRange); - } - } - SetContentRect(rcRet); - return rcRet; -} - -float CPDF_VariableText::GetAutoFontSize() { - int32_t nTotal = sizeof(gFontSizeSteps) / sizeof(uint8_t); - if (IsMultiLine()) - nTotal /= 4; - if (nTotal <= 0) - return 0; - if (GetPlateWidth() <= 0) - return 0; - - int32_t nLeft = 0; - int32_t nRight = nTotal - 1; - int32_t nMid = nTotal / 2; - while (nLeft <= nRight) { - if (IsBigger(gFontSizeSteps[nMid])) - nRight = nMid - 1; - else - nLeft = nMid + 1; - nMid = (nLeft + nRight) / 2; - } - return (float)gFontSizeSteps[nMid]; -} - -bool CPDF_VariableText::IsBigger(float fFontSize) const { - CFX_SizeF szTotal; - for (const auto& pSection : m_SectionArray) { - CFX_SizeF size = pSection->GetSectionSize(fFontSize); - szTotal.width = std::max(size.width, szTotal.width); - szTotal.height += size.height; - if (IsFloatBigger(szTotal.width, GetPlateWidth()) || - IsFloatBigger(szTotal.height, GetPlateHeight())) { - return true; - } - } - return false; -} - -CPVT_FloatRect CPDF_VariableText::RearrangeSections( - const CPVT_WordRange& PlaceRange) { - CPVT_WordPlace place; - float fPosY = 0; - float fOldHeight; - int32_t nSSecIndex = PlaceRange.BeginPos.nSecIndex; - int32_t nESecIndex = PlaceRange.EndPos.nSecIndex; - CPVT_FloatRect rcRet; - for (int32_t s = 0, sz = pdfium::CollectionSize<int32_t>(m_SectionArray); - s < sz; s++) { - place.nSecIndex = s; - CSection* pSection = m_SectionArray[s].get(); - pSection->SecPlace = place; - CPVT_FloatRect rcSec = pSection->m_Rect; - if (s >= nSSecIndex) { - if (s <= nESecIndex) { - rcSec = pSection->Rearrange(); - rcSec.top += fPosY; - rcSec.bottom += fPosY; - } else { - fOldHeight = pSection->m_Rect.bottom - pSection->m_Rect.top; - rcSec.top = fPosY; - rcSec.bottom = fPosY + fOldHeight; - } - pSection->m_Rect = rcSec; - pSection->ResetLinePlace(); - } - if (s == 0) { - rcRet = rcSec; - } else { - rcRet.left = std::min(rcSec.left, rcRet.left); - rcRet.top = std::min(rcSec.top, rcRet.top); - rcRet.right = std::max(rcSec.right, rcRet.right); - rcRet.bottom = std::max(rcSec.bottom, rcRet.bottom); - } - fPosY += rcSec.Height(); - } - return rcRet; -} - -uint32_t CPDF_VariableText::GetCharWidth(int32_t nFontIndex, - uint16_t Word, - uint16_t SubWord) { - if (!m_pVTProvider) - return 0; - uint16_t word = SubWord ? SubWord : Word; - return m_pVTProvider->GetCharWidth(nFontIndex, word); -} - -int32_t CPDF_VariableText::GetTypeAscent(int32_t nFontIndex) { - return m_pVTProvider ? m_pVTProvider->GetTypeAscent(nFontIndex) : 0; -} - -int32_t CPDF_VariableText::GetTypeDescent(int32_t nFontIndex) { - return m_pVTProvider ? m_pVTProvider->GetTypeDescent(nFontIndex) : 0; -} - -int32_t CPDF_VariableText::GetWordFontIndex(uint16_t word, - int32_t charset, - int32_t nFontIndex) { - return m_pVTProvider - ? m_pVTProvider->GetWordFontIndex(word, charset, nFontIndex) - : -1; -} - -int32_t CPDF_VariableText::GetDefaultFontIndex() { - return m_pVTProvider ? m_pVTProvider->GetDefaultFontIndex() : -1; -} - -bool CPDF_VariableText::IsLatinWord(uint16_t word) { - return m_pVTProvider && m_pVTProvider->IsLatinWord(word); -} - -CPDF_VariableText::Iterator* CPDF_VariableText::GetIterator() { - if (!m_pVTIterator) - m_pVTIterator = pdfium::MakeUnique<CPDF_VariableText::Iterator>(this); - return m_pVTIterator.get(); -} - -void CPDF_VariableText::SetProvider(CPDF_VariableText::Provider* pProvider) { - m_pVTProvider = pProvider; -} - -CFX_PointF CPDF_VariableText::GetBTPoint() const { - return CFX_PointF(m_rcPlate.left, m_rcPlate.top); -} - -CFX_PointF CPDF_VariableText::GetETPoint() const { - return CFX_PointF(m_rcPlate.right, m_rcPlate.bottom); -} - -CFX_PointF CPDF_VariableText::InToOut(const CFX_PointF& point) const { - return CFX_PointF(point.x + GetBTPoint().x, GetBTPoint().y - point.y); -} - -CFX_PointF CPDF_VariableText::OutToIn(const CFX_PointF& point) const { - return CFX_PointF(point.x - GetBTPoint().x, GetBTPoint().y - point.y); -} - -CFX_FloatRect CPDF_VariableText::InToOut(const CPVT_FloatRect& rect) const { - CFX_PointF ptLeftTop = InToOut(CFX_PointF(rect.left, rect.top)); - CFX_PointF ptRightBottom = InToOut(CFX_PointF(rect.right, rect.bottom)); - return CFX_FloatRect(ptLeftTop.x, ptRightBottom.y, ptRightBottom.x, - ptLeftTop.y); -} - -CPVT_FloatRect CPDF_VariableText::OutToIn(const CFX_FloatRect& rect) const { - CFX_PointF ptLeftTop = OutToIn(CFX_PointF(rect.left, rect.top)); - CFX_PointF ptRightBottom = OutToIn(CFX_PointF(rect.right, rect.bottom)); - return CPVT_FloatRect(ptLeftTop.x, ptLeftTop.y, ptRightBottom.x, - ptRightBottom.y); -}
diff --git a/core/fpdfdoc/cpdf_variabletext.h b/core/fpdfdoc/cpdf_variabletext.h deleted file mode 100644 index aa47015..0000000 --- a/core/fpdfdoc/cpdf_variabletext.h +++ /dev/null
@@ -1,212 +0,0 @@ -// Copyright 2016 PDFium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com - -#ifndef CORE_FPDFDOC_CPDF_VARIABLETEXT_H_ -#define CORE_FPDFDOC_CPDF_VARIABLETEXT_H_ - -#include <memory> -#include <vector> - -#include "core/fpdfdoc/cpvt_floatrect.h" -#include "core/fpdfdoc/cpvt_line.h" -#include "core/fpdfdoc/cpvt_lineinfo.h" -#include "core/fpdfdoc/cpvt_wordplace.h" -#include "core/fpdfdoc/cpvt_wordrange.h" -#include "core/fxcrt/fx_coordinates.h" -#include "core/fxcrt/fx_string.h" -#include "core/fxcrt/fx_system.h" -#include "core/fxcrt/unowned_ptr.h" - -class CPVT_Word; -class CSection; -class IPVT_FontMap; -struct CPVT_WordInfo; - -#define VARIABLETEXT_HALF 0.5f - -class CPDF_VariableText { - public: - class Iterator { - public: - explicit Iterator(CPDF_VariableText* pVT); - ~Iterator(); - - bool NextWord(); - bool PrevWord(); - bool NextLine(); - bool GetWord(CPVT_Word& word) const; - bool GetLine(CPVT_Line& line) const; - void SetAt(int32_t nWordIndex); - void SetAt(const CPVT_WordPlace& place); - const CPVT_WordPlace& GetWordPlace() const { return m_CurPos; } - - private: - CPVT_WordPlace m_CurPos; - UnownedPtr<CPDF_VariableText> const m_pVT; - }; - - class Provider { - public: - explicit Provider(IPVT_FontMap* pFontMap); - virtual ~Provider(); - - virtual uint32_t GetCharWidth(int32_t nFontIndex, uint16_t word); - virtual int32_t GetTypeAscent(int32_t nFontIndex); - virtual int32_t GetTypeDescent(int32_t nFontIndex); - virtual int32_t GetWordFontIndex(uint16_t word, - int32_t charset, - int32_t nFontIndex); - virtual bool IsLatinWord(uint16_t word); - virtual int32_t GetDefaultFontIndex(); - - private: - UnownedPtr<IPVT_FontMap> const m_pFontMap; - }; - - CPDF_VariableText(); - ~CPDF_VariableText(); - - void SetProvider(CPDF_VariableText::Provider* pProvider); - CPDF_VariableText::Iterator* GetIterator(); - - void SetContentRect(const CPVT_FloatRect& rect); - CFX_FloatRect GetContentRect() const; - void SetPlateRect(const CFX_FloatRect& rect); - const CFX_FloatRect& GetPlateRect() const; - - void SetAlignment(int32_t nFormat) { m_nAlignment = nFormat; } - void SetPasswordChar(uint16_t wSubWord) { m_wSubWord = wSubWord; } - void SetLimitChar(int32_t nLimitChar) { m_nLimitChar = nLimitChar; } - void SetCharSpace(float fCharSpace) { m_fCharSpace = fCharSpace; } - void SetMultiLine(bool bMultiLine) { m_bMultiLine = bMultiLine; } - void SetAutoReturn(bool bAuto) { m_bLimitWidth = bAuto; } - void SetFontSize(float fFontSize) { m_fFontSize = fFontSize; } - void SetCharArray(int32_t nCharArray) { m_nCharArray = nCharArray; } - void SetAutoFontSize(bool bAuto) { m_bAutoFontSize = bAuto; } - void Initialize(); - - bool IsValid() const { return m_bInitialized; } - - void RearrangeAll(); - void RearrangePart(const CPVT_WordRange& PlaceRange); - void SetText(const WideString& text); - CPVT_WordPlace InsertWord(const CPVT_WordPlace& place, - uint16_t word, - int32_t charset); - CPVT_WordPlace InsertSection(const CPVT_WordPlace& place); - CPVT_WordPlace DeleteWords(const CPVT_WordRange& PlaceRange); - CPVT_WordPlace DeleteWord(const CPVT_WordPlace& place); - CPVT_WordPlace BackSpaceWord(const CPVT_WordPlace& place); - - int32_t GetTotalWords() const; - float GetFontSize() const { return m_fFontSize; } - int32_t GetAlignment() const { return m_nAlignment; } - uint16_t GetPasswordChar() const { return GetSubWord(); } - int32_t GetCharArray() const { return m_nCharArray; } - int32_t GetLimitChar() const { return m_nLimitChar; } - bool IsMultiLine() const { return m_bMultiLine; } - float GetCharSpace() const { return m_fCharSpace; } - bool IsAutoReturn() const { return m_bLimitWidth; } - - CPVT_WordPlace GetBeginWordPlace() const; - CPVT_WordPlace GetEndWordPlace() const; - CPVT_WordPlace GetPrevWordPlace(const CPVT_WordPlace& place) const; - CPVT_WordPlace GetNextWordPlace(const CPVT_WordPlace& place) const; - CPVT_WordPlace SearchWordPlace(const CFX_PointF& point) const; - CPVT_WordPlace GetUpWordPlace(const CPVT_WordPlace& place, - const CFX_PointF& point) const; - CPVT_WordPlace GetDownWordPlace(const CPVT_WordPlace& place, - const CFX_PointF& point) const; - CPVT_WordPlace GetLineBeginPlace(const CPVT_WordPlace& place) const; - CPVT_WordPlace GetLineEndPlace(const CPVT_WordPlace& place) const; - CPVT_WordPlace GetSectionBeginPlace(const CPVT_WordPlace& place) const; - CPVT_WordPlace GetSectionEndPlace(const CPVT_WordPlace& place) const; - void UpdateWordPlace(CPVT_WordPlace& place) const; - CPVT_WordPlace AdjustLineHeader(const CPVT_WordPlace& place, - bool bPrevOrNext) const; - int32_t WordPlaceToWordIndex(const CPVT_WordPlace& place) const; - CPVT_WordPlace WordIndexToWordPlace(int32_t index) const; - - uint16_t GetSubWord() const { return m_wSubWord; } - - float GetPlateWidth() const { return m_rcPlate.right - m_rcPlate.left; } - float GetPlateHeight() const { return m_rcPlate.top - m_rcPlate.bottom; } - CFX_PointF GetBTPoint() const; - CFX_PointF GetETPoint() const; - - CFX_PointF InToOut(const CFX_PointF& point) const; - CFX_PointF OutToIn(const CFX_PointF& point) const; - CFX_FloatRect InToOut(const CPVT_FloatRect& rect) const; - CPVT_FloatRect OutToIn(const CFX_FloatRect& rect) const; - - float GetFontAscent(int32_t nFontIndex, float fFontSize); - float GetFontDescent(int32_t nFontIndex, float fFontSize); - int32_t GetDefaultFontIndex(); - float GetLineLeading(); - int32_t GetAlignment(); - float GetWordWidth(const CPVT_WordInfo& WordInfo); - float GetWordWidth(int32_t nFontIndex, - uint16_t Word, - uint16_t SubWord, - float fCharSpace, - float fFontSize, - float fWordTail); - float GetWordAscent(const CPVT_WordInfo& WordInfo); - float GetWordDescent(const CPVT_WordInfo& WordInfo); - float GetWordAscent(const CPVT_WordInfo& WordInfo, float fFontSize); - float GetWordDescent(const CPVT_WordInfo& WordInfo, float fFontSize); - float GetLineAscent(); - float GetLineDescent(); - float GetLineIndent(); - - private: - uint32_t GetCharWidth(int32_t nFontIndex, uint16_t Word, uint16_t SubWord); - int32_t GetTypeAscent(int32_t nFontIndex); - int32_t GetTypeDescent(int32_t nFontIndex); - int32_t GetWordFontIndex(uint16_t word, int32_t charset, int32_t nFontIndex); - bool IsLatinWord(uint16_t word); - - CPVT_WordPlace AddSection(const CPVT_WordPlace& place); - CPVT_WordPlace AddLine(const CPVT_WordPlace& place, - const CPVT_LineInfo& lineinfo); - CPVT_WordPlace AddWord(const CPVT_WordPlace& place, - const CPVT_WordInfo& wordinfo); - float GetWordFontSize(); - int32_t GetWordFontIndex(const CPVT_WordInfo& WordInfo); - - void ClearSectionRightWords(const CPVT_WordPlace& place); - - bool ClearEmptySection(const CPVT_WordPlace& place); - void ClearEmptySections(const CPVT_WordRange& PlaceRange); - void LinkLatterSection(const CPVT_WordPlace& place); - void ClearWords(const CPVT_WordRange& PlaceRange); - CPVT_WordPlace ClearLeftWord(const CPVT_WordPlace& place); - CPVT_WordPlace ClearRightWord(const CPVT_WordPlace& place); - - CPVT_FloatRect Rearrange(const CPVT_WordRange& PlaceRange); - float GetAutoFontSize(); - bool IsBigger(float fFontSize) const; - CPVT_FloatRect RearrangeSections(const CPVT_WordRange& PlaceRange); - - bool m_bInitialized = false; - bool m_bMultiLine = false; - bool m_bLimitWidth = false; - bool m_bAutoFontSize = false; - uint16_t m_wSubWord = 0; - int32_t m_nLimitChar = 0; - int32_t m_nCharArray = 0; - int32_t m_nAlignment = 0; - float m_fLineLeading = 0.0f; - float m_fCharSpace = 0.0f; - float m_fFontSize = 0.0f; - std::vector<std::unique_ptr<CSection>> m_SectionArray; - UnownedPtr<CPDF_VariableText::Provider> m_pVTProvider; - std::unique_ptr<CPDF_VariableText::Iterator> m_pVTIterator; - CFX_FloatRect m_rcPlate; - CPVT_FloatRect m_rcContent; -}; - -#endif // CORE_FPDFDOC_CPDF_VARIABLETEXT_H_
diff --git a/core/fpdfdoc/cpdf_viewerpreferences.cpp b/core/fpdfdoc/cpdf_viewerpreferences.cpp index be07fdc..e3f15f0 100644 --- a/core/fpdfdoc/cpdf_viewerpreferences.cpp +++ b/core/fpdfdoc/cpdf_viewerpreferences.cpp
@@ -1,4 +1,4 @@ -// Copyright 2016 PDFium Authors. All rights reserved. +// Copyright 2016 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -6,6 +6,7 @@ #include "core/fpdfdoc/cpdf_viewerpreferences.h" +#include "core/fpdfapi/parser/cpdf_array.h" #include "core/fpdfapi/parser/cpdf_dictionary.h" #include "core/fpdfapi/parser/cpdf_document.h" #include "core/fpdfapi/parser/cpdf_name.h" @@ -16,44 +17,45 @@ CPDF_ViewerPreferences::~CPDF_ViewerPreferences() = default; bool CPDF_ViewerPreferences::IsDirectionR2L() const { - const CPDF_Dictionary* pDict = GetViewerPreferences(); - return pDict && pDict->GetStringFor("Direction") == "R2L"; + RetainPtr<const CPDF_Dictionary> pDict = GetViewerPreferences(); + return pDict && pDict->GetByteStringFor("Direction") == "R2L"; } bool CPDF_ViewerPreferences::PrintScaling() const { - const CPDF_Dictionary* pDict = GetViewerPreferences(); - return !pDict || pDict->GetStringFor("PrintScaling") != "None"; + RetainPtr<const CPDF_Dictionary> pDict = GetViewerPreferences(); + return !pDict || pDict->GetByteStringFor("PrintScaling") != "None"; } int32_t CPDF_ViewerPreferences::NumCopies() const { - const CPDF_Dictionary* pDict = GetViewerPreferences(); + RetainPtr<const CPDF_Dictionary> pDict = GetViewerPreferences(); return pDict ? pDict->GetIntegerFor("NumCopies") : 1; } -CPDF_Array* CPDF_ViewerPreferences::PrintPageRange() const { - CPDF_Dictionary* pDict = GetViewerPreferences(); +RetainPtr<const CPDF_Array> CPDF_ViewerPreferences::PrintPageRange() const { + RetainPtr<const CPDF_Dictionary> pDict = GetViewerPreferences(); return pDict ? pDict->GetArrayFor("PrintPageRange") : nullptr; } ByteString CPDF_ViewerPreferences::Duplex() const { - const CPDF_Dictionary* pDict = GetViewerPreferences(); - return pDict ? pDict->GetStringFor("Duplex") : ByteString("None"); + RetainPtr<const CPDF_Dictionary> pDict = GetViewerPreferences(); + return pDict ? pDict->GetByteStringFor("Duplex") : ByteString("None"); } -Optional<ByteString> CPDF_ViewerPreferences::GenericName( +absl::optional<ByteString> CPDF_ViewerPreferences::GenericName( const ByteString& bsKey) const { - const CPDF_Dictionary* pDict = GetViewerPreferences(); + RetainPtr<const CPDF_Dictionary> pDict = GetViewerPreferences(); if (!pDict) - return {}; + return absl::nullopt; - const CPDF_Name* pName = ToName(pDict->GetObjectFor(bsKey)); + RetainPtr<const CPDF_Name> pName = ToName(pDict->GetObjectFor(bsKey)); if (!pName) - return {}; + return absl::nullopt; return pName->GetString(); } -CPDF_Dictionary* CPDF_ViewerPreferences::GetViewerPreferences() const { - CPDF_Dictionary* pDict = m_pDoc->GetRoot(); +RetainPtr<const CPDF_Dictionary> CPDF_ViewerPreferences::GetViewerPreferences() + const { + const CPDF_Dictionary* pDict = m_pDoc->GetRoot(); return pDict ? pDict->GetDictFor("ViewerPreferences") : nullptr; }
diff --git a/core/fpdfdoc/cpdf_viewerpreferences.h b/core/fpdfdoc/cpdf_viewerpreferences.h index ff2b1c8..3e17048 100644 --- a/core/fpdfdoc/cpdf_viewerpreferences.h +++ b/core/fpdfdoc/cpdf_viewerpreferences.h
@@ -1,4 +1,4 @@ -// Copyright 2016 PDFium Authors. All rights reserved. +// Copyright 2016 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -7,10 +7,12 @@ #ifndef CORE_FPDFDOC_CPDF_VIEWERPREFERENCES_H_ #define CORE_FPDFDOC_CPDF_VIEWERPREFERENCES_H_ -#include "core/fxcrt/fx_string.h" -#include "core/fxcrt/fx_system.h" +#include <stdint.h> + +#include "core/fxcrt/bytestring.h" +#include "core/fxcrt/retain_ptr.h" #include "core/fxcrt/unowned_ptr.h" -#include "third_party/base/optional.h" +#include "third_party/abseil-cpp/absl/types/optional.h" class CPDF_Array; class CPDF_Dictionary; @@ -24,14 +26,14 @@ bool IsDirectionR2L() const; bool PrintScaling() const; int32_t NumCopies() const; - CPDF_Array* PrintPageRange() const; + RetainPtr<const CPDF_Array> PrintPageRange() const; ByteString Duplex() const; // Gets the entry for |bsKey|. - Optional<ByteString> GenericName(const ByteString& bsKey) const; + absl::optional<ByteString> GenericName(const ByteString& bsKey) const; private: - CPDF_Dictionary* GetViewerPreferences() const; + RetainPtr<const CPDF_Dictionary> GetViewerPreferences() const; UnownedPtr<const CPDF_Document> const m_pDoc; };
diff --git a/core/fpdfdoc/cpvt_floatrect.h b/core/fpdfdoc/cpvt_floatrect.h index d302ed0..a9add92 100644 --- a/core/fpdfdoc/cpvt_floatrect.h +++ b/core/fpdfdoc/cpvt_floatrect.h
@@ -1,4 +1,4 @@ -// Copyright 2016 PDFium Authors. All rights reserved. +// Copyright 2016 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file.
diff --git a/core/fpdfdoc/cpvt_fontmap.cpp b/core/fpdfdoc/cpvt_fontmap.cpp index b21bd0d..d26655f 100644 --- a/core/fpdfdoc/cpvt_fontmap.cpp +++ b/core/fpdfdoc/cpvt_fontmap.cpp
@@ -1,4 +1,4 @@ -// Copyright 2016 PDFium Authors. All rights reserved. +// Copyright 2016 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -6,6 +6,8 @@ #include "core/fpdfdoc/cpvt_fontmap.h" +#include <utility> + #include "core/fpdfapi/font/cpdf_font.h" #include "core/fpdfapi/parser/cpdf_dictionary.h" #include "core/fpdfapi/parser/cpdf_document.h" @@ -13,40 +15,37 @@ #include "core/fpdfapi/parser/fpdf_parser_utility.h" #include "core/fpdfdoc/cpdf_interactiveform.h" #include "core/fxcrt/fx_codepage.h" -#include "third_party/base/logging.h" +#include "third_party/base/check.h" +#include "third_party/base/notreached.h" CPVT_FontMap::CPVT_FontMap(CPDF_Document* pDoc, - CPDF_Dictionary* pResDict, - const RetainPtr<CPDF_Font>& pDefFont, + RetainPtr<CPDF_Dictionary> pResDict, + RetainPtr<CPDF_Font> pDefFont, const ByteString& sDefFontAlias) : m_pDocument(pDoc), - m_pResDict(pResDict), - m_pDefFont(pDefFont), + m_pResDict(std::move(pResDict)), + m_pDefFont(std::move(pDefFont)), m_sDefFontAlias(sDefFontAlias) {} -CPVT_FontMap::~CPVT_FontMap() {} +CPVT_FontMap::~CPVT_FontMap() = default; -// static -RetainPtr<CPDF_Font> CPVT_FontMap::GetAnnotSysPDFFont( - CPDF_Document* pDoc, - CPDF_Dictionary* pResDict, - ByteString* sSysFontAlias) { - if (!pDoc || !pResDict) - return nullptr; +void CPVT_FontMap::SetupAnnotSysPDFFont() { + if (!m_pDocument || !m_pResDict) + return; - CPDF_Dictionary* pFormDict = pDoc->GetRoot()->GetDictFor("AcroForm"); RetainPtr<CPDF_Font> pPDFFont = - AddNativeInteractiveFormFont(pFormDict, pDoc, sSysFontAlias); + CPDF_InteractiveForm::AddNativeInteractiveFormFont(m_pDocument, + &m_sSysFontAlias); if (!pPDFFont) - return nullptr; + return; - CPDF_Dictionary* pFontList = pResDict->GetDictFor("Font"); - if (ValidateFontResourceDict(pFontList) && - !pFontList->KeyExist(*sSysFontAlias)) { - pFontList->SetNewFor<CPDF_Reference>(*sSysFontAlias, pDoc, - pPDFFont->GetFontDict()->GetObjNum()); + RetainPtr<CPDF_Dictionary> pFontList = m_pResDict->GetMutableDictFor("Font"); + if (ValidateFontResourceDict(pFontList.Get()) && + !pFontList->KeyExist(m_sSysFontAlias)) { + pFontList->SetNewFor<CPDF_Reference>(m_sSysFontAlias, m_pDocument, + pPDFFont->GetFontDictObjNum()); } - return pPDFFont; + m_pSysFont = std::move(pPDFFont); } RetainPtr<CPDF_Font> CPVT_FontMap::GetPDFFont(int32_t nFontIndex) { @@ -54,10 +53,8 @@ case 0: return m_pDefFont; case 1: - if (!m_pSysFont) { - m_pSysFont = GetAnnotSysPDFFont(m_pDocument.Get(), m_pResDict.Get(), - &m_sSysFontAlias); - } + if (!m_pSysFont) + SetupAnnotSysPDFFont(); return m_pSysFont; default: return nullptr; @@ -69,10 +66,8 @@ case 0: return m_sDefFontAlias; case 1: - if (!m_pSysFont) { - m_pSysFont = GetAnnotSysPDFFont(m_pDocument.Get(), m_pResDict.Get(), - &m_sSysFontAlias); - } + if (!m_pSysFont) + SetupAnnotSysPDFFont(); return m_sSysFontAlias; default: return ByteString(); @@ -80,7 +75,7 @@ } int32_t CPVT_FontMap::GetWordFontIndex(uint16_t word, - int32_t charset, + FX_Charset charset, int32_t nFontIndex) { NOTREACHED(); return 0; @@ -91,7 +86,8 @@ return 0; } -int32_t CPVT_FontMap::CharSetFromUnicode(uint16_t word, int32_t nOldCharset) { +FX_Charset CPVT_FontMap::CharSetFromUnicode(uint16_t word, + FX_Charset nOldCharset) { NOTREACHED(); - return FX_CHARSET_ANSI; + return FX_Charset::kANSI; }
diff --git a/core/fpdfdoc/cpvt_fontmap.h b/core/fpdfdoc/cpvt_fontmap.h index a85afcf..e3add6f 100644 --- a/core/fpdfdoc/cpvt_fontmap.h +++ b/core/fpdfdoc/cpvt_fontmap.h
@@ -1,4 +1,4 @@ -// Copyright 2016 PDFium Authors. All rights reserved. +// Copyright 2016 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -10,7 +10,7 @@ #include <stdint.h> #include "core/fpdfdoc/ipvt_fontmap.h" -#include "core/fxcrt/fx_string.h" +#include "core/fxcrt/bytestring.h" #include "core/fxcrt/retain_ptr.h" #include "core/fxcrt/unowned_ptr.h" @@ -21,8 +21,8 @@ class CPVT_FontMap final : public IPVT_FontMap { public: CPVT_FontMap(CPDF_Document* pDoc, - CPDF_Dictionary* pResDict, - const RetainPtr<CPDF_Font>& pDefFont, + RetainPtr<CPDF_Dictionary> pResDict, + RetainPtr<CPDF_Font> pDefFont, const ByteString& sDefFontAlias); ~CPVT_FontMap() override; @@ -30,16 +30,14 @@ RetainPtr<CPDF_Font> GetPDFFont(int32_t nFontIndex) override; ByteString GetPDFFontAlias(int32_t nFontIndex) override; int32_t GetWordFontIndex(uint16_t word, - int32_t charset, + FX_Charset charset, int32_t nFontIndex) override; int32_t CharCodeFromUnicode(int32_t nFontIndex, uint16_t word) override; - int32_t CharSetFromUnicode(uint16_t word, int32_t nOldCharset) override; - - static RetainPtr<CPDF_Font> GetAnnotSysPDFFont(CPDF_Document* pDoc, - CPDF_Dictionary* pResDict, - ByteString* sSysFontAlias); + FX_Charset CharSetFromUnicode(uint16_t word, FX_Charset nOldCharset) override; private: + void SetupAnnotSysPDFFont(); + UnownedPtr<CPDF_Document> const m_pDocument; RetainPtr<CPDF_Dictionary> const m_pResDict; RetainPtr<CPDF_Font> const m_pDefFont;
diff --git a/core/fpdfdoc/cpvt_generateap.cpp b/core/fpdfdoc/cpvt_generateap.cpp deleted file mode 100644 index 2b90365..0000000 --- a/core/fpdfdoc/cpvt_generateap.cpp +++ /dev/null
@@ -1,1386 +0,0 @@ -// Copyright 2016 PDFium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com - -#include "core/fpdfdoc/cpvt_generateap.h" - -#include <algorithm> -#include <memory> -#include <sstream> -#include <utility> - -#include "constants/annotation_common.h" -#include "constants/form_fields.h" -#include "core/fpdfapi/font/cpdf_font.h" -#include "core/fpdfapi/page/cpdf_docpagedata.h" -#include "core/fpdfapi/parser/cpdf_array.h" -#include "core/fpdfapi/parser/cpdf_boolean.h" -#include "core/fpdfapi/parser/cpdf_dictionary.h" -#include "core/fpdfapi/parser/cpdf_document.h" -#include "core/fpdfapi/parser/cpdf_name.h" -#include "core/fpdfapi/parser/cpdf_number.h" -#include "core/fpdfapi/parser/cpdf_reference.h" -#include "core/fpdfapi/parser/cpdf_stream.h" -#include "core/fpdfapi/parser/cpdf_string.h" -#include "core/fpdfapi/parser/fpdf_parser_decode.h" -#include "core/fpdfapi/parser/fpdf_parser_utility.h" -#include "core/fpdfdoc/cpdf_annot.h" -#include "core/fpdfdoc/cpdf_color_utils.h" -#include "core/fpdfdoc/cpdf_defaultappearance.h" -#include "core/fpdfdoc/cpdf_formfield.h" -#include "core/fpdfdoc/cpdf_variabletext.h" -#include "core/fpdfdoc/cpvt_fontmap.h" -#include "core/fpdfdoc/cpvt_word.h" -#include "core/fxge/cfx_renderdevice.h" -#include "third_party/base/ptr_util.h" - -namespace { - -struct CPVT_Dash { - CPVT_Dash(int32_t dash, int32_t gap, int32_t phase) - : nDash(dash), nGap(gap), nPhase(phase) {} - - int32_t nDash; - int32_t nGap; - int32_t nPhase; -}; - -enum class PaintOperation { STROKE, FILL }; - -ByteString GetPDFWordString(IPVT_FontMap* pFontMap, - int32_t nFontIndex, - uint16_t Word, - uint16_t SubWord) { - if (SubWord > 0) - return ByteString::Format("%c", SubWord); - - if (!pFontMap) - return ByteString(); - - RetainPtr<CPDF_Font> pPDFFont = pFontMap->GetPDFFont(nFontIndex); - if (!pPDFFont) - return ByteString(); - - if (pPDFFont->GetBaseFontName().Compare("Symbol") == 0 || - pPDFFont->GetBaseFontName().Compare("ZapfDingbats") == 0) { - return ByteString::Format("%c", Word); - } - - ByteString sWord; - uint32_t dwCharCode = pPDFFont->CharCodeFromUnicode(Word); - if (dwCharCode != CPDF_Font::kInvalidCharCode) - pPDFFont->AppendChar(&sWord, dwCharCode); - - return sWord; -} - -ByteString GetWordRenderString(const ByteString& strWords) { - if (strWords.GetLength() > 0) - return PDF_EncodeString(strWords, false) + " Tj\n"; - return ByteString(); -} - -ByteString GetFontSetString(IPVT_FontMap* pFontMap, - int32_t nFontIndex, - float fFontSize) { - std::ostringstream sRet; - if (pFontMap) { - ByteString sFontAlias = pFontMap->GetPDFFontAlias(nFontIndex); - if (sFontAlias.GetLength() > 0 && fFontSize > 0) - sRet << "/" << sFontAlias << " " << fFontSize << " Tf\n"; - } - return ByteString(sRet); -} - -ByteString GenerateEditAP(IPVT_FontMap* pFontMap, - CPDF_VariableText::Iterator* pIterator, - const CFX_PointF& ptOffset, - bool bContinuous, - uint16_t SubWord) { - std::ostringstream sEditStream; - std::ostringstream sLineStream; - std::ostringstream sWords; - CFX_PointF ptOld; - CFX_PointF ptNew; - int32_t nCurFontIndex = -1; - CPVT_WordPlace oldplace; - - pIterator->SetAt(0); - while (pIterator->NextWord()) { - CPVT_WordPlace place = pIterator->GetWordPlace(); - if (bContinuous) { - if (place.LineCmp(oldplace) != 0) { - if (sWords.tellp() > 0) { - sLineStream << GetWordRenderString(ByteString(sWords)); - sEditStream << sLineStream.str(); - sLineStream.str(""); - sWords.str(""); - } - CPVT_Word word; - if (pIterator->GetWord(word)) { - ptNew = CFX_PointF(word.ptWord.x + ptOffset.x, - word.ptWord.y + ptOffset.y); - } else { - CPVT_Line line; - pIterator->GetLine(line); - ptNew = CFX_PointF(line.ptLine.x + ptOffset.x, - line.ptLine.y + ptOffset.y); - } - if (ptNew != ptOld) { - sLineStream << ptNew.x - ptOld.x << " " << ptNew.y - ptOld.y - << " Td\n"; - ptOld = ptNew; - } - } - CPVT_Word word; - if (pIterator->GetWord(word)) { - if (word.nFontIndex != nCurFontIndex) { - if (sWords.tellp() > 0) { - sLineStream << GetWordRenderString(ByteString(sWords)); - sWords.str(""); - } - sLineStream << GetFontSetString(pFontMap, word.nFontIndex, - word.fFontSize); - nCurFontIndex = word.nFontIndex; - } - sWords << GetPDFWordString(pFontMap, nCurFontIndex, word.Word, SubWord); - } - oldplace = place; - } else { - CPVT_Word word; - if (pIterator->GetWord(word)) { - ptNew = - CFX_PointF(word.ptWord.x + ptOffset.x, word.ptWord.y + ptOffset.y); - if (ptNew != ptOld) { - sEditStream << ptNew.x - ptOld.x << " " << ptNew.y - ptOld.y - << " Td\n"; - ptOld = ptNew; - } - if (word.nFontIndex != nCurFontIndex) { - sEditStream << GetFontSetString(pFontMap, word.nFontIndex, - word.fFontSize); - nCurFontIndex = word.nFontIndex; - } - sEditStream << GetWordRenderString( - GetPDFWordString(pFontMap, nCurFontIndex, word.Word, SubWord)); - } - } - } - if (sWords.tellp() > 0) { - sLineStream << GetWordRenderString(ByteString(sWords)); - sEditStream << sLineStream.str(); - sWords.str(""); - } - return ByteString(sEditStream); -} - -ByteString GenerateColorAP(const CFX_Color& color, PaintOperation nOperation) { - std::ostringstream sColorStream; - switch (color.nColorType) { - case CFX_Color::kRGB: - sColorStream << color.fColor1 << " " << color.fColor2 << " " - << color.fColor3 << " " - << (nOperation == PaintOperation::STROKE ? "RG" : "rg") - << "\n"; - break; - case CFX_Color::kGray: - sColorStream << color.fColor1 << " " - << (nOperation == PaintOperation::STROKE ? "G" : "g") - << "\n"; - break; - case CFX_Color::kCMYK: - sColorStream << color.fColor1 << " " << color.fColor2 << " " - << color.fColor3 << " " << color.fColor4 << " " - << (nOperation == PaintOperation::STROKE ? "K" : "k") - << "\n"; - break; - case CFX_Color::kTransparent: - break; - } - return ByteString(sColorStream); -} - -ByteString GenerateBorderAP(const CFX_FloatRect& rect, - float fWidth, - const CFX_Color& color, - const CFX_Color& crLeftTop, - const CFX_Color& crRightBottom, - BorderStyle nStyle, - const CPVT_Dash& dash) { - std::ostringstream sAppStream; - ByteString sColor; - float fLeft = rect.left; - float fRight = rect.right; - float fTop = rect.top; - float fBottom = rect.bottom; - if (fWidth > 0.0f) { - float fHalfWidth = fWidth / 2.0f; - switch (nStyle) { - default: - case BorderStyle::SOLID: - sColor = GenerateColorAP(color, PaintOperation::FILL); - if (sColor.GetLength() > 0) { - sAppStream << sColor; - sAppStream << fLeft << " " << fBottom << " " << fRight - fLeft << " " - << fTop - fBottom << " re\n"; - sAppStream << fLeft + fWidth << " " << fBottom + fWidth << " " - << fRight - fLeft - fWidth * 2 << " " - << fTop - fBottom - fWidth * 2 << " re\n"; - sAppStream << "f*\n"; - } - break; - case BorderStyle::DASH: - sColor = GenerateColorAP(color, PaintOperation::STROKE); - if (sColor.GetLength() > 0) { - sAppStream << sColor; - sAppStream << fWidth << " w" - << " [" << dash.nDash << " " << dash.nGap << "] " - << dash.nPhase << " d\n"; - sAppStream << fLeft + fWidth / 2 << " " << fBottom + fWidth / 2 - << " m\n"; - sAppStream << fLeft + fWidth / 2 << " " << fTop - fWidth / 2 - << " l\n"; - sAppStream << fRight - fWidth / 2 << " " << fTop - fWidth / 2 - << " l\n"; - sAppStream << fRight - fWidth / 2 << " " << fBottom + fWidth / 2 - << " l\n"; - sAppStream << fLeft + fWidth / 2 << " " << fBottom + fWidth / 2 - << " l S\n"; - } - break; - case BorderStyle::BEVELED: - case BorderStyle::INSET: - sColor = GenerateColorAP(crLeftTop, PaintOperation::FILL); - if (sColor.GetLength() > 0) { - sAppStream << sColor; - sAppStream << fLeft + fHalfWidth << " " << fBottom + fHalfWidth - << " m\n"; - sAppStream << fLeft + fHalfWidth << " " << fTop - fHalfWidth - << " l\n"; - sAppStream << fRight - fHalfWidth << " " << fTop - fHalfWidth - << " l\n"; - sAppStream << fRight - fHalfWidth * 2 << " " << fTop - fHalfWidth * 2 - << " l\n"; - sAppStream << fLeft + fHalfWidth * 2 << " " << fTop - fHalfWidth * 2 - << " l\n"; - sAppStream << fLeft + fHalfWidth * 2 << " " - << fBottom + fHalfWidth * 2 << " l f\n"; - } - sColor = GenerateColorAP(crRightBottom, PaintOperation::FILL); - if (sColor.GetLength() > 0) { - sAppStream << sColor; - sAppStream << fRight - fHalfWidth << " " << fTop - fHalfWidth - << " m\n"; - sAppStream << fRight - fHalfWidth << " " << fBottom + fHalfWidth - << " l\n"; - sAppStream << fLeft + fHalfWidth << " " << fBottom + fHalfWidth - << " l\n"; - sAppStream << fLeft + fHalfWidth * 2 << " " - << fBottom + fHalfWidth * 2 << " l\n"; - sAppStream << fRight - fHalfWidth * 2 << " " - << fBottom + fHalfWidth * 2 << " l\n"; - sAppStream << fRight - fHalfWidth * 2 << " " << fTop - fHalfWidth * 2 - << " l f\n"; - } - sColor = GenerateColorAP(color, PaintOperation::FILL); - if (sColor.GetLength() > 0) { - sAppStream << sColor; - sAppStream << fLeft << " " << fBottom << " " << fRight - fLeft << " " - << fTop - fBottom << " re\n"; - sAppStream << fLeft + fHalfWidth << " " << fBottom + fHalfWidth << " " - << fRight - fLeft - fHalfWidth * 2 << " " - << fTop - fBottom - fHalfWidth * 2 << " re f*\n"; - } - break; - case BorderStyle::UNDERLINE: - sColor = GenerateColorAP(color, PaintOperation::STROKE); - if (sColor.GetLength() > 0) { - sAppStream << sColor; - sAppStream << fWidth << " w\n"; - sAppStream << fLeft << " " << fBottom + fWidth / 2 << " m\n"; - sAppStream << fRight << " " << fBottom + fWidth / 2 << " l S\n"; - } - break; - } - } - return ByteString(sAppStream); -} - -ByteString GetColorStringWithDefault(CPDF_Array* pColor, - const CFX_Color& crDefaultColor, - PaintOperation nOperation) { - if (pColor) { - CFX_Color color = fpdfdoc::CFXColorFromArray(*pColor); - return GenerateColorAP(color, nOperation); - } - - return GenerateColorAP(crDefaultColor, nOperation); -} - -float GetBorderWidth(const CPDF_Dictionary& pAnnotDict) { - if (const CPDF_Dictionary* pBorderStyleDict = pAnnotDict.GetDictFor("BS")) { - if (pBorderStyleDict->KeyExist("W")) - return pBorderStyleDict->GetNumberFor("W"); - } - - if (const CPDF_Array* pBorderArray = - pAnnotDict.GetArrayFor(pdfium::annotation::kBorder)) { - if (pBorderArray->size() > 2) - return pBorderArray->GetNumberAt(2); - } - - return 1; -} - -const CPDF_Array* GetDashArray(const CPDF_Dictionary& pAnnotDict) { - if (const CPDF_Dictionary* pBorderStyleDict = pAnnotDict.GetDictFor("BS")) { - if (pBorderStyleDict->GetStringFor("S") == "D") - return pBorderStyleDict->GetArrayFor("D"); - } - - if (const CPDF_Array* pBorderArray = - pAnnotDict.GetArrayFor(pdfium::annotation::kBorder)) { - if (pBorderArray->size() == 4) - return pBorderArray->GetArrayAt(3); - } - - return nullptr; -} - -ByteString GetDashPatternString(const CPDF_Dictionary& pAnnotDict) { - const CPDF_Array* pDashArray = GetDashArray(pAnnotDict); - if (!pDashArray || pDashArray->IsEmpty()) - return ByteString(); - - // Support maximum of ten elements in the dash array. - size_t pDashArrayCount = std::min<size_t>(pDashArray->size(), 10); - std::ostringstream sDashStream; - - sDashStream << "["; - for (size_t i = 0; i < pDashArrayCount; ++i) - sDashStream << pDashArray->GetNumberAt(i) << " "; - sDashStream << "] 0 d\n"; - - return ByteString(sDashStream); -} - -ByteString GetPopupContentsString(CPDF_Document* pDoc, - const CPDF_Dictionary& pAnnotDict, - const RetainPtr<CPDF_Font>& pDefFont, - const ByteString& sFontName) { - WideString swValue(pAnnotDict.GetUnicodeTextFor(pdfium::form_fields::kT)); - swValue += L'\n'; - swValue += pAnnotDict.GetUnicodeTextFor(pdfium::annotation::kContents); - CPVT_FontMap map(pDoc, nullptr, pDefFont, sFontName); - - CPDF_VariableText::Provider prd(&map); - CPDF_VariableText vt; - vt.SetProvider(&prd); - vt.SetPlateRect(pAnnotDict.GetRectFor(pdfium::annotation::kRect)); - vt.SetFontSize(12); - vt.SetAutoReturn(true); - vt.SetMultiLine(true); - - vt.Initialize(); - vt.SetText(swValue); - vt.RearrangeAll(); - CFX_PointF ptOffset(3.0f, -3.0f); - ByteString sContent = - GenerateEditAP(&map, vt.GetIterator(), ptOffset, false, 0); - - if (sContent.IsEmpty()) - return ByteString(); - - std::ostringstream sAppStream; - sAppStream << "BT\n" - << GenerateColorAP(CFX_Color(CFX_Color::kRGB, 0, 0, 0), - PaintOperation::FILL) - << sContent << "ET\n" - << "Q\n"; - return ByteString(sAppStream); -} - -RetainPtr<CPDF_Dictionary> GenerateResourceFontDict( - CPDF_Document* pDoc, - const ByteString& sFontDictName) { - CPDF_Dictionary* pFontDict = pDoc->NewIndirect<CPDF_Dictionary>(); - pFontDict->SetNewFor<CPDF_Name>("Type", "Font"); - pFontDict->SetNewFor<CPDF_Name>("Subtype", "Type1"); - pFontDict->SetNewFor<CPDF_Name>("BaseFont", CFX_Font::kDefaultAnsiFontName); - pFontDict->SetNewFor<CPDF_Name>("Encoding", "WinAnsiEncoding"); - - auto pResourceFontDict = pDoc->New<CPDF_Dictionary>(); - pResourceFontDict->SetNewFor<CPDF_Reference>(sFontDictName, pDoc, - pFontDict->GetObjNum()); - return pResourceFontDict; -} - -ByteString GetPaintOperatorString(bool bIsStrokeRect, bool bIsFillRect) { - if (bIsStrokeRect) - return bIsFillRect ? "b" : "s"; - return bIsFillRect ? "f" : "n"; -} - -ByteString GenerateTextSymbolAP(const CFX_FloatRect& rect) { - std::ostringstream sAppStream; - sAppStream << GenerateColorAP(CFX_Color(CFX_Color::kRGB, 1, 1, 0), - PaintOperation::FILL); - sAppStream << GenerateColorAP(CFX_Color(CFX_Color::kRGB, 0, 0, 0), - PaintOperation::STROKE); - - const float fBorderWidth = 1; - sAppStream << fBorderWidth << " w\n"; - - const float fHalfWidth = fBorderWidth / 2; - const float fTipDelta = 4; - - CFX_FloatRect outerRect1 = rect; - outerRect1.Deflate(fHalfWidth, fHalfWidth); - outerRect1.bottom += fTipDelta; - - CFX_FloatRect outerRect2 = outerRect1; - outerRect2.left += fTipDelta; - outerRect2.right = outerRect2.left + fTipDelta; - outerRect2.top = outerRect2.bottom - fTipDelta; - float outerRect2Middle = (outerRect2.left + outerRect2.right) / 2; - - // Draw outer boxes. - sAppStream << outerRect1.left << " " << outerRect1.bottom << " m\n" - << outerRect1.left << " " << outerRect1.top << " l\n" - << outerRect1.right << " " << outerRect1.top << " l\n" - << outerRect1.right << " " << outerRect1.bottom << " l\n" - << outerRect2.right << " " << outerRect2.bottom << " l\n" - << outerRect2Middle << " " << outerRect2.top << " l\n" - << outerRect2.left << " " << outerRect2.bottom << " l\n" - << outerRect1.left << " " << outerRect1.bottom << " l\n"; - - // Draw inner lines. - CFX_FloatRect lineRect = outerRect1; - const float fXDelta = 2; - const float fYDelta = (lineRect.top - lineRect.bottom) / 4; - - lineRect.left += fXDelta; - lineRect.right -= fXDelta; - for (int i = 0; i < 3; ++i) { - lineRect.top -= fYDelta; - sAppStream << lineRect.left << " " << lineRect.top << " m\n" - << lineRect.right << " " << lineRect.top << " l\n"; - } - sAppStream << "B*\n"; - - return ByteString(sAppStream); -} - -RetainPtr<CPDF_Dictionary> GenerateExtGStateDict( - const CPDF_Dictionary& pAnnotDict, - const ByteString& sExtGSDictName, - const ByteString& sBlendMode) { - auto pGSDict = - pdfium::MakeRetain<CPDF_Dictionary>(pAnnotDict.GetByteStringPool()); - pGSDict->SetNewFor<CPDF_Name>("Type", "ExtGState"); - - float fOpacity = - pAnnotDict.KeyExist("CA") ? pAnnotDict.GetNumberFor("CA") : 1; - pGSDict->SetNewFor<CPDF_Number>("CA", fOpacity); - pGSDict->SetNewFor<CPDF_Number>("ca", fOpacity); - pGSDict->SetNewFor<CPDF_Boolean>("AIS", false); - pGSDict->SetNewFor<CPDF_Name>("BM", sBlendMode); - - auto pExtGStateDict = - pdfium::MakeRetain<CPDF_Dictionary>(pAnnotDict.GetByteStringPool()); - pExtGStateDict->SetFor(sExtGSDictName, pGSDict); - return pExtGStateDict; -} - -RetainPtr<CPDF_Dictionary> GenerateResourceDict( - CPDF_Document* pDoc, - RetainPtr<CPDF_Dictionary> pExtGStateDict, - RetainPtr<CPDF_Dictionary> pResourceFontDict) { - auto pResourceDict = pDoc->New<CPDF_Dictionary>(); - if (pExtGStateDict) - pResourceDict->SetFor("ExtGState", pExtGStateDict); - if (pResourceFontDict) - pResourceDict->SetFor("Font", pResourceFontDict); - return pResourceDict; -} - -void GenerateAndSetAPDict(CPDF_Document* pDoc, - CPDF_Dictionary* pAnnotDict, - std::ostringstream* psAppStream, - RetainPtr<CPDF_Dictionary> pResourceDict, - bool bIsTextMarkupAnnotation) { - CPDF_Stream* pNormalStream = pDoc->NewIndirect<CPDF_Stream>(); - pNormalStream->SetDataFromStringstream(psAppStream); - - CPDF_Dictionary* pAPDict = pAnnotDict->GetDictFor(pdfium::annotation::kAP); - if (!pAPDict) - pAPDict = pAnnotDict->SetNewFor<CPDF_Dictionary>(pdfium::annotation::kAP); - - pAPDict->SetNewFor<CPDF_Reference>("N", pDoc, pNormalStream->GetObjNum()); - - CPDF_Dictionary* pStreamDict = pNormalStream->GetDict(); - pStreamDict->SetNewFor<CPDF_Number>("FormType", 1); - pStreamDict->SetNewFor<CPDF_Name>("Type", "XObject"); - pStreamDict->SetNewFor<CPDF_Name>("Subtype", "Form"); - pStreamDict->SetMatrixFor("Matrix", CFX_Matrix()); - - CFX_FloatRect rect = bIsTextMarkupAnnotation - ? CPDF_Annot::BoundingRectFromQuadPoints(pAnnotDict) - : pAnnotDict->GetRectFor(pdfium::annotation::kRect); - pStreamDict->SetRectFor("BBox", rect); - pStreamDict->SetFor("Resources", pResourceDict); -} - -bool GenerateCircleAP(CPDF_Document* pDoc, CPDF_Dictionary* pAnnotDict) { - std::ostringstream sAppStream; - ByteString sExtGSDictName = "GS"; - sAppStream << "/" << sExtGSDictName << " gs "; - - CPDF_Array* pInteriorColor = pAnnotDict->GetArrayFor("IC"); - sAppStream << GetColorStringWithDefault( - pInteriorColor, CFX_Color(CFX_Color::kTransparent), PaintOperation::FILL); - - sAppStream << GetColorStringWithDefault( - pAnnotDict->GetArrayFor(pdfium::annotation::kC), - CFX_Color(CFX_Color::kRGB, 0, 0, 0), PaintOperation::STROKE); - - float fBorderWidth = GetBorderWidth(*pAnnotDict); - bool bIsStrokeRect = fBorderWidth > 0; - - if (bIsStrokeRect) { - sAppStream << fBorderWidth << " w "; - sAppStream << GetDashPatternString(*pAnnotDict); - } - - CFX_FloatRect rect = pAnnotDict->GetRectFor(pdfium::annotation::kRect); - rect.Normalize(); - - if (bIsStrokeRect) { - // Deflating rect because stroking a path entails painting all points whose - // perpendicular distance from the path in user space is less than or equal - // to half the line width. - rect.Deflate(fBorderWidth / 2, fBorderWidth / 2); - } - - const float fMiddleX = (rect.left + rect.right) / 2; - const float fMiddleY = (rect.top + rect.bottom) / 2; - - // |fL| is precalculated approximate value of 4 * tan((3.14 / 2) / 4) / 3, - // where |fL| * radius is a good approximation of control points for - // arc with 90 degrees. - const float fL = 0.5523f; - const float fDeltaX = fL * rect.Width() / 2.0; - const float fDeltaY = fL * rect.Height() / 2.0; - - // Starting point - sAppStream << fMiddleX << " " << rect.top << " m\n"; - // First Bezier Curve - sAppStream << fMiddleX + fDeltaX << " " << rect.top << " " << rect.right - << " " << fMiddleY + fDeltaY << " " << rect.right << " " - << fMiddleY << " c\n"; - // Second Bezier Curve - sAppStream << rect.right << " " << fMiddleY - fDeltaY << " " - << fMiddleX + fDeltaX << " " << rect.bottom << " " << fMiddleX - << " " << rect.bottom << " c\n"; - // Third Bezier Curve - sAppStream << fMiddleX - fDeltaX << " " << rect.bottom << " " << rect.left - << " " << fMiddleY - fDeltaY << " " << rect.left << " " << fMiddleY - << " c\n";