Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 7 additions & 10 deletions core/fpdfapi/parser/fpdf_parser_decode_embeddertest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,36 +2,34 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "build/build_config.h"
#include "core/fpdfapi/parser/fpdf_parser_decode.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;

TEST_F(FPDFParserDecodeEmbedderTest, Bug552046) {
// Tests specifying multiple image filters for a stream. Should not cause a
// crash when rendered.
// crash when rendered and should produce a blank page.
ASSERT_TRUE(OpenDocument("bug_552046.pdf"));
ScopedPage page = LoadScopedPage(0);
ASSERT_TRUE(page);
ScopedFPDFBitmap bitmap = RenderLoadedPage(page.get());
CompareBitmap(bitmap.get(), pdfium::kBlankPage612By792Png);
CompareDisplayList(RenderLoadedPageToDisplayList(page.get()),
"blank_page_612x792");
}

TEST_F(FPDFParserDecodeEmbedderTest, Bug555784) {
// Tests bad input to the run length decoder that caused a heap overflow.
// Should not cause a crash when rendered. The image is 81915 pixels wide
// with 3277 DeviceN components at 16 bits each, which is a valid but
// enourmous pitch, so its one scanline does get decoded and drawn.
// enormous pitch, so its one scanline does get decoded and drawn.
ASSERT_TRUE(OpenDocument("bug_555784.pdf"));
ScopedPage page = LoadScopedPage(0);
ASSERT_TRUE(page);
ScopedFPDFBitmap bitmap = RenderLoadedPage(page.get());
CompareBitmap(bitmap.get(), "bug_555784");
CompareDisplayList(RenderLoadedPageToDisplayList(page.get()), "bug_555784");
}

TEST_F(FPDFParserDecodeEmbedderTest, Bug455199) {
Expand All @@ -40,6 +38,5 @@ TEST_F(FPDFParserDecodeEmbedderTest, Bug455199) {
ASSERT_TRUE(OpenDocument("bug_455199.pdf"));
ScopedPage page = LoadScopedPage(0);
ASSERT_TRUE(page);
ScopedFPDFBitmap bitmap = RenderLoadedPage(page.get());
CompareBitmapWithExpectationSuffix(bitmap.get(), pdfium::kHelloWorldPng);
CompareDisplayList(RenderLoadedPageToDisplayList(page.get()), "hello_world");
}
6 changes: 3 additions & 3 deletions core/fxcodec/jpx/cjpx_decoder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -97,9 +97,9 @@ void sycc_to_rgb(int offset,
int* out_b) {
cb -= offset;
cr -= offset;
*out_r = std::clamp(y + static_cast<int>(1.402 * cr), 0, upb);
*out_g = std::clamp(y - static_cast<int>(0.344 * cb + 0.714 * cr), 0, upb);
*out_b = std::clamp(y + static_cast<int>(1.772 * cb), 0, upb);
*out_r = std::clamp(y + static_cast<int>(1.402f * cr), 0, upb);
*out_g = std::clamp(y - static_cast<int>(0.344f * cb + 0.714f * cr), 0, upb);
*out_b = std::clamp(y + static_cast<int>(1.772f * cb), 0, upb);
}

pdfium::span<opj_image_comp_t> components_span(opj_image_t* img) {
Expand Down
71 changes: 61 additions & 10 deletions core/fxge/cfx_face.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
#include "core/fxcrt/check_op.h"
#include "core/fxcrt/compiler_specific.h"
#include "core/fxcrt/fixed_size_data_vector.h"
#include "core/fxcrt/fx_extension.h"
#include "core/fxcrt/notreached.h"
#include "core/fxcrt/numerics/clamped_math.h"
#include "core/fxcrt/numerics/safe_conversions.h"
Expand Down Expand Up @@ -53,24 +54,21 @@

namespace {

// Boundary value to avoid integer overflow when adding 1/64th of the value.
constexpr int kMaxRectTop = 2114445437;

#if defined(PDF_ENABLE_FREETYPE)
constexpr int kThousandthMinInt = std::numeric_limits<int>::min() / 1000;
constexpr int kThousandthMaxInt = std::numeric_limits<int>::max() / 1000;
constexpr int kMaxGlyphDimension = 2048;
#endif // defined(PDF_ENABLE_FREETYPE)

// Boundary value to avoid integer overflow when adding 1/64th of the value.
constexpr int kMaxRectTop = 2114445437;
constexpr float kCoordUnit = 64 * 64.0f;

#if defined(PDF_ENABLE_FREETYPE)
struct OUTLINE_PARAMS {
UnownedPtr<CFX_Path> path_;
FT_Pos cur_x_;
FT_Pos cur_y_;
};

constexpr float kCoordUnit = 64 * 64.0f;

int FTPosToCBoxInt(FT_Pos pos) {
// Boundary values to avoid integer overflow when multiplied by 1000.
static constexpr FT_Pos kMinCBox = -2147483;
Expand Down Expand Up @@ -509,6 +507,57 @@ class ScopedFaceVariation {
};
#endif // defined(PDF_ENABLE_FREETYPE)

#if defined(PDF_ENABLE_FONTATIONS)
wchar_t UnicodeFromZapfDingbatsName(const char* name) {
ByteStringView name_view(name);
if (name_view.GetLength() < 2) {
return 0;
}
if (name_view.Front() != 'a') {
return 0;
}
uint32_t val = 0;
for (char c : name_view.Substr(1)) {
if (!FXSYS_IsDecimalDigit(c)) {
return 0;
}
val = val * 10 + FXSYS_DecimalCharToInt(c);
if (val > 206) {
return 0;
}
}
if (val == 0) {
return 0;
}
static constexpr std::array<uint16_t, 206> kZapfGlyphs = {
0x2701, 0x2702, 0x2704, 0x260e, 0x2706, 0x271d, 0x271e, 0x271f, 0x2720,
0x2721, 0x261b, 0x261e, 0x270c, 0x270d, 0x270e, 0x270f, 0x2711, 0x2712,
0x2713, 0x2714, 0x2715, 0x2716, 0x2717, 0x2718, 0x2719, 0x271a, 0x271b,
0x271c, 0x2722, 0x2723, 0x2724, 0x2725, 0x2726, 0x2727, 0x2605, 0x2729,
0x272a, 0x272b, 0x272c, 0x272d, 0x272e, 0x272f, 0x2730, 0x2731, 0x2732,
0x2733, 0x2734, 0x2735, 0x2736, 0x2737, 0x2738, 0x2739, 0x273a, 0x273b,
0x273c, 0x273d, 0x273e, 0x273f, 0x2740, 0x2741, 0x2742, 0x2743, 0x2744,
0x2745, 0x2746, 0x2747, 0x2748, 0x2749, 0x274a, 0x274b, 0x25cf, 0x274d,
0x25a0, 0x274f, 0x2751, 0x25b2, 0x25bc, 0x25c6, 0x2756, 0x0000, 0x25d7,
0x2758, 0x2759, 0x275a, 0x276f, 0x2771, 0x2772, 0x2773, 0x2768, 0x2769,
0x276c, 0x276d, 0x276a, 0x276b, 0x2774, 0x2775, 0x275b, 0x275c, 0x275d,
0x275e, 0x2761, 0x2762, 0x2763, 0x2764, 0x2710, 0x2765, 0x2766, 0x2767,
0x2660, 0x2665, 0x2666, 0x2663, 0x0000, 0x0000, 0x0000, 0x0000, 0x2709,
0x2708, 0x2707, 0x2460, 0x2461, 0x2462, 0x2463, 0x2464, 0x2465, 0x2466,
0x2467, 0x2468, 0x2469, 0x2776, 0x2777, 0x2778, 0x2779, 0x277a, 0x277b,
0x277c, 0x277d, 0x277e, 0x277f, 0x2780, 0x2781, 0x2782, 0x2783, 0x2784,
0x2785, 0x2786, 0x2787, 0x2788, 0x2789, 0x278a, 0x278b, 0x278c, 0x278d,
0x278e, 0x278f, 0x2790, 0x2791, 0x2792, 0x2793, 0x2794, 0x2192, 0x27a3,
0x2194, 0x2195, 0x2799, 0x279b, 0x279c, 0x279d, 0x279e, 0x279f, 0x27a0,
0x27a1, 0x27a2, 0x27a4, 0x27a5, 0x27a6, 0x27a7, 0x27a8, 0x27a9, 0x27ab,
0x27ad, 0x27af, 0x27b2, 0x27b3, 0x27b5, 0x27b8, 0x27ba, 0x27bb, 0x27bc,
0x27bd, 0x27be, 0x279a, 0x27aa, 0x27b6, 0x27b9, 0x2798, 0x27b4, 0x27b7,
0x27ac, 0x27ae, 0x27b1, 0x2703, 0x2750, 0x2752, 0x276e, 0x2770,
};
return kZapfGlyphs[val - 1];
}
#endif // defined(PDF_ENABLE_FONTATIONS)

} // namespace

#if defined(PDF_ENABLE_FONTATIONS)
Expand Down Expand Up @@ -566,12 +615,14 @@ RetainPtr<CFX_Face> CFX_Face::New(RetainPtr<Retainable> cache_entry,

// static
wchar_t CFX_Face::UnicodeFromAdobeName(const char* name) {
CHECK(name);
#if defined(PDF_ENABLE_FONTATIONS)
if (CFX_GEModule::IsFontations()) {
uint32_t unicode = 0;
return skrifa::agl_name_to_unicode(name, unicode)
? static_cast<wchar_t>(unicode)
: 0;
if (skrifa::agl_name_to_unicode(name, unicode)) {
return static_cast<wchar_t>(unicode);
}
return UnicodeFromZapfDingbatsName(name);
}
#endif // defined(PDF_ENABLE_FONTATIONS)
#if defined(PDF_ENABLE_FREETYPE)
Expand Down
96 changes: 96 additions & 0 deletions docs/embedpdf/syncs/2026-10-19-9c866a447.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
# Sync 2026-10-19: upstream 7c55203ed..9c866a447 (9 commits)

## Summary

Upstream from 2026-10-16 to 2026-10-16, merged into `b6d182352`.

Upstream moved four more groups of embedder tests (annotation, parser decode, page import, flatten)
to display-list comparisons and deleted their PNG goldens. It also added ZapfDingbats names to the
fontations name lookup and fixed an XFA FormCalc lifetime. We took upstream's tests, dropped the Mac
goldens they replace, and kept our substitute-font fix next to upstream's new table. The layer-mode
harness now keeps form drawing out of display lists too, as it already did for bitmaps.

## Likely security fixes

None.

## Conflicts (6 files, 2 blocks)

A block with an `EPDF_TLS` count is never resolved by taking upstream's side without putting `EPDF_TLS` back (rule thread-confined-globals).

| File | Blocks | Rules in the blocks | EPDF_TLS | Upstream commits | Resolution |
| :-- | --: | :-- | --: | :-- | :-- |
| `core/fxge/cfx_face.cpp` | 1 | substitute-font-bounds | | `c3e1143e8` Use display list comparisons in flatten embedder tests | Both: our `ScopedFaceVariation` (substitute-font-bounds), then upstream's `UnicodeFromZapfDingbatsName()` (fontations only, not in our builds). |
| `fpdfsdk/fpdf_flatten_embeddertest.cpp` | 1 | untagged | | `c3e1143e8` Use display list comparisons in flatten embedder tests | Upstream's `VerifySavedDocumentWithDisplayList("blank_100x120", FPDF_ANNOT)`. Ours only pointed the old check at a Mac golden (`ef8389fe2`); our `blank_100x120_agg_mac.png` goes with it. |
| `testing/resources/embedder_tests/annots_page1_agg_mac.png` | binary, rename or delete | untagged | | `e804c9576` Use display list comparisons in annotation embedder tests | Deleted, as upstream did: the test compares a display list now. |
| `testing/resources/embedder_tests/annots_page1_focus_highlight_agg_mac.png` | binary, rename or delete | untagged | | `e804c9576` Use display list comparisons in annotation embedder tests | Deleted, as upstream did: the test compares a display list now. |
| `testing/resources/embedder_tests/annots_page1_focus_link_agg_mac.png` | binary, rename or delete | untagged | | `e804c9576` Use display list comparisons in annotation embedder tests | Deleted, as upstream did: the test compares a display list now. |
| `testing/resources/embedder_tests/bug_861842_agg_mac.png` | binary, rename or delete | untagged | | `c3e1143e8` Use display list comparisons in flatten embedder tests | Deleted, as upstream did: the test compares a display list now. |

## Write audit (0 lines)

None.

## Upstream changes outside the conflicts

- **Display-list tests.** `e804c9576` (annotation), `02aeb0078` (parser decode), `f14ea7f3d` (page
import), `c3e1143e8` (flatten) and `067393bda` (`DeletePageAndRender`) compare display lists
instead of PNGs. Six of our Mac pixel failures go away with them.
- **Layer-mode harness (rule layer-mode).** The display-list renderer draws the form through the
form handle (`GetOrCreatePageView()`), and the form-fill page view isn't layer-safe. `RenderPageWithFlags()`
already skips `FPDF_FFLDraw` in layer mode; `RenderPageWithFlagsToDisplayList()` now drops the
handle the same way. Without it, the flatten tests `Bug889099`, `Bug890322` and `Bug896366` hit
the layer's write assertions in layer mode instead of failing as expected.
- **XFA FormCalc (`c9a34bc1d`, `a50f1a595`).** The context's destructor clears the binding of its
value, and a date-symbols loop drops an `UNSAFE_TODO`. Not in our builds (`pdf_enable_xfa=false`).
- **JPX `sycc_to_rgb()` (`9c866a447`)** uses float literals; same results.
- **lcms (`bb72e525b`)** removes a stale patch file; no code change.

## Upstream appearance generator

None.

## Globals

No new globals by the heuristic. `check-globals.py` on the darwin-arm64 release build: ok.

## Build and patches

- `DEPS` changed in 0 commits; no `gclient sync` needed.
- All of `patches/embedpdf-runtime/` apply (darwin-arm64 and wasm32 locally; CI applies every
target's).

## API diff

None from upstream. The darwin-arm64 exports differ from S11's only by what `embedpdf/main` merged
since then: #80 replaces `EPDFBookmark_*` with `EPDFOutline_*`, #81 adds
`EPDFPage_ExportRawToOwnedBuffer` and `EPDFPage_ImportRaw`.

## Tests

- [x] fork unit + embedder tests (darwin-arm64): 1286 unit tests pass. Embedder: 1655 tests,
9 skipped, 30 failing, every one a PNG pixel comparison against a Mac golden; the same 30 failed
in S11, whose other six (`AddAndSaveLinkAnnotation`, `FocusableAnnotRendering`, `Bug861842`,
`Bug889099`, `ImportWithZeroLengthStream`, `Bug455199`) compare display lists now and pass.
Linux runs in the PR's CI.
- [x] layer mode: exit 0, no warnings; 213 layer-only failures, all expected; writers unchanged
(270). The four new layer-only failures are form drawing, already in the expectations:
`Bug861842`, `Bug889099` and `FocusableAnnotRendering` failed the plain Mac run before, and
`FPDFFormFillEmbedderTest.Bug1302455RenderOnly` no longer gets the form drawn into its display
list. `FPDFFormFillEmbedderTest.RemoveFormFieldHighlight` fails instead of crashing. (A Mac
recording drops the Linux-only `TransFormWithClipAndSaveWithLocale`; its line stays.)
- [x] tag check (`--base 9c866a447`): 975 blocks, 0 untagged.
- [x] C API check: ok, 527 functions in 23 headers (the outline and page-capture merges on main).
- [x] globals check: ok.
- [x] wasm build: builds locally.
- [ ] ThreadSanitizer soak: in the PR's CI.
- [ ] engine tests and engine-conformance with the local runtime: not run for this sync.
- changed expectations, each with its reason:
- `FPDFFlattenEmbedderTest.Bug861842`, `Bug889099`, `Bug890322`, `Bug896366` (layer mode): same
entries, reason reworded from "Pixel test of a form" since they compare display lists now.
- `FPDFFlattenEmbedderTest.Bug861842`: upstream's display list replaces our Mac golden
`blank_100x120_agg_mac.png`.

## Ledger changes proposed

None.
Loading