done phase 1 code base
This commit is contained in:
+1
-1
@@ -33,7 +33,7 @@ endif()
|
||||
add_library(skia::skia STATIC IMPORTED GLOBAL)
|
||||
set_target_properties(skia::skia PROPERTIES
|
||||
IMPORTED_LOCATION "${SKIA_LIBRARY}"
|
||||
INTERFACE_INCLUDE_DIRECTORIES "${SKIA_INCLUDE_DIR}/include")
|
||||
INTERFACE_INCLUDE_DIRECTORIES "${SKIA_INCLUDE_DIR}")
|
||||
|
||||
if(UNIX AND NOT APPLE)
|
||||
set_property(TARGET skia::skia APPEND PROPERTY
|
||||
|
||||
@@ -13,6 +13,7 @@ add_library(pdfengine STATIC
|
||||
src/core/engine_info.cpp
|
||||
src/core/graphics_state.cpp
|
||||
src/core/display_list.cpp
|
||||
src/core/skia_renderer.cpp
|
||||
src/parser/pdfium_loader.cpp
|
||||
src/parser/pdfium_document.cpp
|
||||
src/fonts/font_face.cpp
|
||||
@@ -44,7 +45,7 @@ endif()
|
||||
|
||||
if(PDFENGINE_WITH_SKIA)
|
||||
target_link_libraries(pdfengine PRIVATE skia::skia)
|
||||
target_compile_definitions(pdfengine PRIVATE PDFENGINE_WITH_SKIA)
|
||||
target_compile_definitions(pdfengine PUBLIC PDFENGINE_WITH_SKIA)
|
||||
endif()
|
||||
|
||||
pdfengine_set_warnings(pdfengine)
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
#pragma once
|
||||
|
||||
#include <pdfengine/display_list.hpp>
|
||||
#include <pdfengine/graphics_state.hpp>
|
||||
|
||||
class SkCanvas;
|
||||
|
||||
namespace pdfengine {
|
||||
|
||||
// A visitor that replays a DisplayList onto a Skia canvas.
|
||||
class SkiaRenderer : public CommandVisitor {
|
||||
public:
|
||||
// Takes a pointer to an external SkCanvas.
|
||||
// The caller is responsible for the canvas's lifecycle.
|
||||
explicit SkiaRenderer(SkCanvas* canvas);
|
||||
|
||||
void visit(const SaveStateCommand& cmd) override;
|
||||
void visit(const RestoreStateCommand& cmd) override;
|
||||
void visit(const SetTransformCommand& cmd) override;
|
||||
void visit(const FillRectCommand& cmd) override;
|
||||
void visit(const DrawTextCommand& cmd) override;
|
||||
|
||||
// Renders the entire display list to the canvas
|
||||
void render(const DisplayList& displayList);
|
||||
|
||||
private:
|
||||
SkCanvas* m_canvas;
|
||||
GraphicsStateStack m_stateStack;
|
||||
};
|
||||
|
||||
} // namespace pdfengine
|
||||
@@ -0,0 +1,96 @@
|
||||
#include "pdfengine/skia_renderer.hpp"
|
||||
|
||||
#ifdef PDFENGINE_WITH_SKIA
|
||||
#include <include/core/SkCanvas.h>
|
||||
#include <include/core/SkPaint.h>
|
||||
#include <include/core/SkMatrix.h>
|
||||
#include <include/core/SkFont.h>
|
||||
#include <include/core/SkTypeface.h>
|
||||
#endif
|
||||
|
||||
namespace pdfengine {
|
||||
|
||||
SkiaRenderer::SkiaRenderer(SkCanvas* canvas) : m_canvas(canvas) {}
|
||||
|
||||
void SkiaRenderer::render(const DisplayList& displayList) {
|
||||
if (!m_canvas) return;
|
||||
|
||||
// Iterate and accept commands
|
||||
displayList.replay(*this);
|
||||
}
|
||||
|
||||
void SkiaRenderer::visit(const SaveStateCommand& cmd) {
|
||||
(void)cmd;
|
||||
#ifdef PDFENGINE_WITH_SKIA
|
||||
if (m_canvas) m_canvas->save();
|
||||
#endif
|
||||
m_stateStack.push();
|
||||
}
|
||||
|
||||
void SkiaRenderer::visit(const RestoreStateCommand& cmd) {
|
||||
(void)cmd;
|
||||
#ifdef PDFENGINE_WITH_SKIA
|
||||
if (m_canvas) m_canvas->restore();
|
||||
#endif
|
||||
m_stateStack.pop();
|
||||
}
|
||||
|
||||
void SkiaRenderer::visit(const SetTransformCommand& cmd) {
|
||||
#ifdef PDFENGINE_WITH_SKIA
|
||||
if (m_canvas) {
|
||||
SkMatrix skMatrix;
|
||||
// Map 2D affine matrix to Skia's 3x3 matrix
|
||||
// [ a c e ] (Skia) vs [ a b 0 ]
|
||||
// [ b d f ] [ c d 0 ]
|
||||
// [ 0 0 1 ] [ e f 1 ]
|
||||
skMatrix.setAll(
|
||||
cmd.matrix.a, cmd.matrix.c, cmd.matrix.e,
|
||||
cmd.matrix.b, cmd.matrix.d, cmd.matrix.f,
|
||||
0.0f, 0.0f, 1.0f
|
||||
);
|
||||
m_canvas->concat(skMatrix);
|
||||
}
|
||||
#endif
|
||||
// Also update internal state if we need it later
|
||||
m_stateStack.current().ctm = m_stateStack.current().ctm.multiply(cmd.matrix);
|
||||
}
|
||||
|
||||
void SkiaRenderer::visit(const FillRectCommand& cmd) {
|
||||
#ifdef PDFENGINE_WITH_SKIA
|
||||
if (!m_canvas) return;
|
||||
|
||||
SkPaint paint;
|
||||
paint.setAntiAlias(true);
|
||||
|
||||
const auto& color = m_stateStack.current().fillColor;
|
||||
paint.setColor(SkColorSetARGB(255,
|
||||
static_cast<uint8_t>(color.r * 255),
|
||||
static_cast<uint8_t>(color.g * 255),
|
||||
static_cast<uint8_t>(color.b * 255)));
|
||||
|
||||
SkRect rect = SkRect::MakeXYWH(cmd.x, cmd.y, cmd.width, cmd.height);
|
||||
m_canvas->drawRect(rect, paint);
|
||||
#endif
|
||||
}
|
||||
|
||||
void SkiaRenderer::visit(const DrawTextCommand& cmd) {
|
||||
#ifdef PDFENGINE_WITH_SKIA
|
||||
if (!m_canvas) return;
|
||||
|
||||
SkPaint paint;
|
||||
paint.setAntiAlias(true);
|
||||
|
||||
const auto& color = m_stateStack.current().fillColor;
|
||||
paint.setColor(SkColorSetARGB(255,
|
||||
static_cast<uint8_t>(color.r * 255),
|
||||
static_cast<uint8_t>(color.g * 255),
|
||||
static_cast<uint8_t>(color.b * 255)));
|
||||
|
||||
// For phase 0/1 testing, we use a default typeface
|
||||
SkFont font(nullptr, 12.0f);
|
||||
|
||||
m_canvas->drawString(cmd.text.c_str(), cmd.x, cmd.y, font, paint);
|
||||
#endif
|
||||
}
|
||||
|
||||
} // namespace pdfengine
|
||||
@@ -6,6 +6,7 @@ add_executable(pdfengine_smoke
|
||||
graphics_state_test.cpp
|
||||
display_list_test.cpp
|
||||
document_test.cpp
|
||||
skia_renderer_test.cpp
|
||||
)
|
||||
|
||||
target_link_libraries(pdfengine_smoke
|
||||
@@ -15,6 +16,10 @@ target_link_libraries(pdfengine_smoke
|
||||
GTest::gtest_main
|
||||
)
|
||||
|
||||
if(PDFENGINE_WITH_SKIA)
|
||||
target_link_libraries(pdfengine_smoke PRIVATE skia::skia)
|
||||
endif()
|
||||
|
||||
target_include_directories(pdfengine_smoke
|
||||
PRIVATE
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/../src"
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
#include <gtest/gtest.h>
|
||||
#include <pdfengine/display_list.hpp>
|
||||
#include <pdfengine/skia_renderer.hpp>
|
||||
|
||||
#ifdef PDFENGINE_WITH_SKIA
|
||||
#include <include/core/SkBitmap.h>
|
||||
#include <include/core/SkCanvas.h>
|
||||
#endif
|
||||
|
||||
using namespace pdfengine;
|
||||
|
||||
TEST(SkiaRendererTest, RenderSimpleDisplayList) {
|
||||
#ifdef PDFENGINE_WITH_SKIA
|
||||
SkBitmap bitmap;
|
||||
bitmap.allocN32Pixels(100, 100);
|
||||
SkCanvas canvas(bitmap);
|
||||
canvas.clear(SK_ColorWHITE);
|
||||
|
||||
DisplayList dl;
|
||||
// Push state and set fill color to red
|
||||
dl.saveState();
|
||||
dl.fillRect(10, 10, 50, 50); // Will be filled with red (we need a SetFillColorCommand, but right now GraphicsState doesn't expose it directly via Command yet. It will use default black)
|
||||
dl.restoreState();
|
||||
|
||||
SkiaRenderer renderer(&canvas);
|
||||
renderer.render(dl);
|
||||
|
||||
// Let's verify that a pixel at (20,20) was drawn. Since default color is black (0,0,0), we check that.
|
||||
SkColor c = bitmap.getColor(20, 20);
|
||||
EXPECT_EQ(SkColorGetR(c), 0);
|
||||
EXPECT_EQ(SkColorGetG(c), 0);
|
||||
EXPECT_EQ(SkColorGetB(c), 0);
|
||||
|
||||
// Check outside the rect
|
||||
SkColor bg = bitmap.getColor(5, 5);
|
||||
EXPECT_EQ(SkColorGetR(bg), 255);
|
||||
EXPECT_EQ(SkColorGetG(bg), 255);
|
||||
EXPECT_EQ(SkColorGetB(bg), 255);
|
||||
#else
|
||||
GTEST_SKIP() << "PDFENGINE_WITH_SKIA not defined. Skia tests skipped.";
|
||||
#endif
|
||||
}
|
||||
Binary file not shown.
Reference in New Issue
Block a user