done phase 1 code base

This commit is contained in:
azeeee05
2026-05-25 10:34:39 +05:30
parent 52cef2cecf
commit 21b9390e48
7 changed files with 177 additions and 2 deletions
+1 -1
View File
@@ -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
+2 -1
View File
@@ -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
+96
View File
@@ -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
+5
View File
@@ -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"
+42
View File
@@ -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.