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
19 changes: 18 additions & 1 deletion core/fpdfdoc/cpdf_documentfonts.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -463,9 +463,26 @@ void CPDF_DocumentFonts::Forget(const std::set<uint32_t>& objnums) {
inspected_.erase(objnum);
}
for (auto& [objnum, inspected] : inspected_) {
std::set<DataVector<uint8_t>> read_by_changed;
std::erase_if(inspected.display_of_dict, [&](const auto& entry) {
return objnums.contains(entry.first);
if (!objnums.contains(entry.first)) {
return false;
}
if (entry.second.has_value()) {
read_by_changed.insert(*entry.second);
}
return true;
});
// A display only a changed dictionary read is no longer the document's,
// so its hash finds nothing.
for (const DataVector<uint8_t>& sha256 : read_by_changed) {
const bool still_read = std::ranges::any_of(
inspected.display_of_dict,
[&](const auto& entry) { return entry.second == sha256; });
if (!still_read) {
inspected.displays.erase(sha256);
}
}
}
}

Expand Down
3 changes: 2 additions & 1 deletion core/fpdfdoc/cpdf_documentfonts.h
Original file line number Diff line number Diff line change
Expand Up @@ -200,7 +200,8 @@ class CPDF_DocumentFonts final : public CPDF_Document::FontIndex {
std::optional<Display> aligned;
// Display programs by their SHA-256. Any other program is read through
// each font dictionary's encoding, widths and flags, so one stream can
// be drawn as more than one.
// be drawn as more than one. A display goes when the last dictionary that
// read it changes.
std::map<DataVector<uint8_t>, Display> displays;
// The display each font dictionary (by object number) reads the stream
// as; nullopt when it builds none. Forgotten when the dictionary
Expand Down
11 changes: 7 additions & 4 deletions docs/embedpdf/fork-ledger.md
Original file line number Diff line number Diff line change
Expand Up @@ -491,12 +491,15 @@ race.
### layer-mode
**Rule.** With `EPDF_EMBEDDER_LAYER_MODE=1`, the embedder test harness opens every file as a fresh
layer over a frozen base. Like the engine, it sends the form-fill environment no page events and
doesn't draw with it.
doesn't draw with it. A document a test builds in memory goes through the layer too when the test
opens it with `EmbedderTest::OpenDocumentFromMemory()`, or with
`embedpdf_test::LoadMemDocumentForTest()` when it keeps the document itself; a test that writes
into a new document starts from `EmptyPdf()`, since `CreateEmptyDocument()` never makes a layer.
**Why.** Upstream's embedder tests then run through the layer's read and write paths, so a new
upstream feature is tested on a layer without anyone writing a layer test.
**Where.** `testing/embedpdf_layer_mode.{h,cpp}`, four hooks in `testing/embedder_test.cpp`,
`testing/tools/run_layer_mode.py` with `testing/embedpdf_layer_mode_expectations.txt` and
`testing/embedpdf_layer_mode_writers.txt`.
**Where.** `testing/embedpdf_layer_mode.{h,cpp}`, the `EmbedPDF(layer-mode)` hooks in
`testing/embedder_test.{h,cpp}`, `testing/tools/run_layer_mode.py` with
`testing/embedpdf_layer_mode_expectations.txt` and `testing/embedpdf_layer_mode_writers.txt`.
**Guarded by.** `run_layer_mode.py` fails when no test leaves an object in a layer, which is what
happens when a hook stops working.
**When upstream touches this.** `EmbedderTest`'s document opening, page loading and page
Expand Down
14 changes: 10 additions & 4 deletions fpdfsdk/epdf_annot_embeddertest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@
#include "core/fxge/cfx_font.h"
#include "core/fxge/cfx_fontregistry.h"
#include "fpdfsdk/cpdfsdk_helpers.h"
#include "fpdfsdk/epdf_edit_test_util.h"
#include "public/cpp/fpdf_scopers.h"
#include "public/epdf_edit.h"
#include "public/epdf_flatten.h"
Expand All @@ -76,6 +77,7 @@
#include "testing/embedder_test_constants.h"
#include "testing/embedpdf_form_writes.h"
#include "testing/embedpdf_layer_fixture.h"
#include "testing/embedpdf_layer_mode.h"
#include "testing/fx_string_testhelpers.h"
#include "testing/gmock/include/gmock/gmock-matchers.h"
#include "testing/utils/file_util.h"
Expand Down Expand Up @@ -4303,7 +4305,9 @@ TEST_F(EPDFAnnotEmbedderTest, RichTextLastResortDrawsWhatNoFontHas) {

std::string saved;
{
ScopedFPDFDocument doc(FPDF_CreateNewDocument());
const std::string empty = EmptyPdf();
embedpdf_test::ScopedTestDocument doc(embedpdf_test::LoadMemDocumentForTest(
empty.data(), empty.size(), nullptr));
ScopedFPDFPage page(FPDFPage_New(doc.get(), 0, 400, 400));
ScopedFPDFAnnotation annot(
FPDFPage_CreateAnnot(page.get(), FPDF_ANNOT_FREETEXT));
Expand Down Expand Up @@ -4337,8 +4341,8 @@ TEST_F(EPDFAnnotEmbedderTest, RichTextLastResortDrawsWhatNoFontHas) {
saved.assign(static_cast<const char*>(saved_buffer), saved_size);
EPDF_FreeBuffer(saved_buffer);
}
ScopedFPDFDocument doc(FPDF_LoadMemDocument(
saved.data(), static_cast<int>(saved.size()), nullptr));
embedpdf_test::ScopedTestDocument doc(embedpdf_test::LoadMemDocumentForTest(
saved.data(), saved.size(), nullptr));
ASSERT_TRUE(doc);
ScopedFPDFPage page(FPDF_LoadPage(doc.get(), 0));
ASSERT_TRUE(page);
Expand Down Expand Up @@ -4367,7 +4371,9 @@ TEST_F(EPDFAnnotEmbedderTest, RichTextPreviewAndPrintLastResortWaits) {
ASSERT_NE(0u, box_id);
ASSERT_TRUE(EPDFFont_SetLastResortFont(box_id));

ScopedFPDFDocument doc(FPDF_CreateNewDocument());
const std::string empty = EmptyPdf();
embedpdf_test::ScopedTestDocument doc(embedpdf_test::LoadMemDocumentForTest(
empty.data(), empty.size(), nullptr));
ScopedFPDFPage page(FPDFPage_New(doc.get(), 0, 400, 400));
const char kJson[] =
"{\"body\":{\"family\":\"Roboto\",\"size\":18},"
Expand Down
7 changes: 7 additions & 0 deletions fpdfsdk/epdf_edit_test_util.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,13 @@ std::string MakePdf(const std::vector<std::string>& objects) {
return pdf;
}

std::string EmptyPdf() {
return MakePdf({
"<< /Type /Catalog /Pages 2 0 R >>",
"<< /Type /Pages /Kids [] /Count 0 >>",
});
}

std::string Stream(const std::string& data) {
return Stream("", data);
}
Expand Down
6 changes: 6 additions & 0 deletions fpdfsdk/epdf_edit_test_util.h
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,12 @@ inline constexpr uint8_t kBluePng[] = {
// A PDF of the given object bodies, numbered from 1, with a classic xref.
std::string MakePdf(const std::vector<std::string>& objects);

// A PDF with no pages, for a test that writes into a document of its own.
// Opened with EmbedderTest::OpenDocumentFromMemory() or
// embedpdf_test::LoadMemDocumentForTest(), it is a layer in layer mode, as
// every document the engine opens is; CreateEmptyDocument() never is.
std::string EmptyPdf();

// A stream object body holding `data`.
std::string Stream(const std::string& data);

Expand Down
Loading