blob: 81430df06846c48528ab148bc87ab33e1464d26d [file] [log] [blame]
// 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/fxge/win32/cfx_psrenderer.h"
#include "core/fxcrt/bytestring.h"
#include "core/fxcrt/data_vector.h"
#include "core/fxcrt/fx_coordinates.h"
#include "core/fxcrt/fx_stream.h"
#include "core/fxcrt/retain_ptr.h"
#include "core/fxge/dib/cfx_dibitmap.h"
#include "core/fxge/dib/fx_dib.h"
#include "core/fxge/win32/cfx_psfonttracker.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/abseil-cpp/absl/types/optional.h"
#include "third_party/base/span.h"
namespace {
DataVector<uint8_t> FakeA85Encode(pdfium::span<const uint8_t> src_span) {
return DataVector<uint8_t>({'d', 'u', 'm', 'm', 'y', 'a', '8', '5'});
}
class TestWriteStream final : public IFX_RetainableWriteStream {
public:
CONSTRUCT_VIA_MAKE_RETAIN;
// IFX_RetainableWriteStream:
bool WriteBlock(pdfium::span<const uint8_t> buffer) override {
data_.insert(data_.end(), buffer.begin(), buffer.end());
return true;
}
pdfium::span<const uint8_t> GetSpan() const { return data_; }
private:
DataVector<uint8_t> data_;
};
} // namespace
TEST(PSRendererTest, GenerateType42SfntData) {
absl::optional<ByteString> result;
result = CFX_PSRenderer::GenerateType42SfntDataForTesting("empty", {});
EXPECT_FALSE(result.has_value());
constexpr uint8_t kOddByteCountTestData[] = {0, 32, 55};
static constexpr char kExpectedOddByteCountResult[] = R"(/odd_sfnts [
<
002037
>
] def
)";
result = CFX_PSRenderer::GenerateType42SfntDataForTesting(
"odd", kOddByteCountTestData);
ASSERT_TRUE(result.has_value());
EXPECT_STREQ(kExpectedOddByteCountResult, result.value().c_str());
// Requires padding.
constexpr uint8_t kEvenByteCountTestData[] = {0, 32, 66, 77};
static constexpr char kExpectedEvenByteCountResult[] = R"(/even_sfnts [
<
0020424D00
>
] def
)";
result = CFX_PSRenderer::GenerateType42SfntDataForTesting(
"even", kEvenByteCountTestData);
ASSERT_TRUE(result.has_value());
EXPECT_STREQ(kExpectedEvenByteCountResult, result.value().c_str());
}
TEST(PSRendererTest, GenerateType42FontDictionary) {
ByteString result;
static constexpr char kExpected1DescendantFontResult[] = R"(8 dict begin
/FontType 42 def
/FontMatrix [1 0 0 1 0 0] def
/FontName /1descendant_0 def
/Encoding 3 array
dup 0 /c00 put
dup 1 /c01 put
dup 2 /c02 put
readonly def
/FontBBox [1 2 3 4] def
/PaintType 0 def
/CharStrings 4 dict dup begin
/.notdef 0 def
/c00 0 def
/c01 1 def
/c02 2 def
end readonly def
/sfnts 1descendant_sfnts def
FontName currentdict end definefont pop
6 dict begin
/FontName /1descendant def
/FontType 0 def
/FontMatrix [1 0 0 1 0 0] def
/FMapType 2 def
/Encoding [
0
] def
/FDepVector [
/1descendant_0 findfont
] def
FontName currentdict end definefont pop
%%EndResource
)";
result = CFX_PSRenderer::GenerateType42FontDictionaryForTesting(
"1descendant", FX_RECT(1, 2, 3, 4), /*num_glyphs=*/3,
/*glyphs_per_descendant_font=*/3);
EXPECT_STREQ(kExpected1DescendantFontResult, result.c_str());
static constexpr char kExpected2DescendantFontResult[] = R"(8 dict begin
/FontType 42 def
/FontMatrix [1 0 0 1 0 0] def
/FontName /2descendant_0 def
/Encoding 3 array
dup 0 /c00 put
dup 1 /c01 put
dup 2 /c02 put
readonly def
/FontBBox [12 -5 34 199] def
/PaintType 0 def
/CharStrings 4 dict dup begin
/.notdef 0 def
/c00 0 def
/c01 1 def
/c02 2 def
end readonly def
/sfnts 2descendant_sfnts def
FontName currentdict end definefont pop
8 dict begin
/FontType 42 def
/FontMatrix [1 0 0 1 0 0] def
/FontName /2descendant_1 def
/Encoding 3 array
dup 0 /c00 put
dup 1 /c01 put
readonly def
/FontBBox [12 -5 34 199] def
/PaintType 0 def
/CharStrings 4 dict dup begin
/.notdef 0 def
/c00 3 def
/c01 4 def
end readonly def
/sfnts 2descendant_sfnts def
FontName currentdict end definefont pop
6 dict begin
/FontName /2descendant def
/FontType 0 def
/FontMatrix [1 0 0 1 0 0] def
/FMapType 2 def
/Encoding [
0
1
] def
/FDepVector [
/2descendant_0 findfont
/2descendant_1 findfont
] def
FontName currentdict end definefont pop
%%EndResource
)";
result = CFX_PSRenderer::GenerateType42FontDictionaryForTesting(
"2descendant", FX_RECT(12, -5, 34, 199), /*num_glyphs=*/5,
/*glyphs_per_descendant_font=*/3);
EXPECT_STREQ(kExpected2DescendantFontResult, result.c_str());
}
TEST(PSRendererTest, DrawDIBits) {
static constexpr char kExpectedOutput[] = R"(
save
/im/initmatrix load def
/n/newpath load def/m/moveto load def/l/lineto load def/c/curveto load def/h/closepath load def
/f/fill load def/F/eofill load def/s/stroke load def/W/clip load def/W*/eoclip load def
/rg/setrgbcolor load def/k/setcmykcolor load def
/J/setlinecap load def/j/setlinejoin load def/w/setlinewidth load def/M/setmiterlimit load def/d/setdash load def
/q/gsave load def/Q/grestore load def/iM/imagemask load def
/Tj/show load def/Ff/findfont load def/Fs/scalefont load def/Sf/setfont load def
/cm/concat load def/Cm/currentmatrix load def/mx/matrix load def/sm/setmatrix load def
q
[1 0 0 1 0 0]cm 10 2 1[10 0 0 -2 0 2]currentfile/ASCII85Decode filter false 1 colorimage
dummya85
Q
restore
)";
auto output_stream = pdfium::MakeRetain<TestWriteStream>();
{
constexpr int kWidth = 10;
constexpr int kHeight = 2;
CFX_PSFontTracker font_tracker;
const EncoderIface encoder_interface{&FakeA85Encode, nullptr, nullptr,
nullptr, nullptr};
CFX_PSRenderer renderer(&font_tracker, &encoder_interface);
renderer.Init(output_stream, CFX_PSRenderer::RenderingLevel::kLevel2,
kWidth, kHeight);
auto bitmap = pdfium::MakeRetain<CFX_DIBitmap>();
bool result = bitmap->Create(kWidth, kHeight, FXDIB_Format::k1bppRgb);
ASSERT_TRUE(result);
bitmap->Clear(0);
ASSERT_TRUE(renderer.DrawDIBits(bitmap, /*color=*/0, CFX_Matrix(),
FXDIB_ResampleOptions()));
}
ByteString output(output_stream->GetSpan());
EXPECT_STREQ(output.c_str(), kExpectedOutput);
}