Skip to content
Closed
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
2 changes: 1 addition & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -222,7 +222,7 @@ if (PAG_BUILD_PAGX)
file(GLOB_RECURSE HTML_EXPORTER_SOURCES src/pagx/html/*.*)
list(APPEND PAG_FILES ${HTML_EXPORTER_SOURCES})

# woff2 encoder + brotli (for embedded font → WOFF2 conversion in HTML exporter)
# woff2 encoder + brotli (for embedded font → WOFF2 conversion in HTML/SVG exporters)
set(WOFF2_DIR third_party/woff2)
set(BROTLI_DIR ${WOFF2_DIR}/brotli)
set(WOFF2_SOURCES
Expand Down
13 changes: 13 additions & 0 deletions include/pagx/SVGExporter.h
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,19 @@ struct SVGExportOptions {
* default of HTMLExportOptions::rasterScale.
*/
float rasterScale = 2.0f;

/**
* Whether to embed vector Font resources as WOFF2 @font-face rules with base64 data URIs and
* render their Text elements via <text> with PUA Unicode characters. When enabled, Text
* nodes whose GlyphRun references an embeddable vector Font become real <text> elements —
* selectable, searchable, and animatable per character — instead of opaque outline <path>
* elements. Bitmap (CBDT) fonts and GlyphRuns that carry per-glyph scales / skews remain on the
* outline path because plain SVG <text> cannot express them. When disabled, every Text
* with GlyphRun data is emitted as <path> (the legacy behaviour). Has no effect when
* `convertTextToPath` is true (the user has explicitly requested outline geometry). The default
* value is true.
*/
bool embedFontsAsWoff2 = true;
};

/**
Expand Down
2 changes: 1 addition & 1 deletion src/pagx/html/HTMLExporter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,9 @@
#include "pagx/html/HTMLBuilder.h"
#include "pagx/html/HTMLStyleExtractor.h"
#include "pagx/html/HTMLWriter.h"
#include "pagx/html/Woff2FontGenerator.h"
#include "pagx/nodes/Font.h"
#include "pagx/utils/StringParser.h"
#include "pagx/utils/Woff2FontGenerator.h"

namespace pagx {

Expand Down
13 changes: 1 addition & 12 deletions src/pagx/html/HTMLWriter.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@
#include "pagx/html/FontSignature.h"
#include "pagx/html/HTMLBuilder.h"
#include "pagx/html/HTMLPlusDarkerRenderer.h"
#include "pagx/html/Woff2FontGenerator.h"
#include "pagx/nodes/ColorSource.h"
#include "pagx/nodes/ColorStop.h"
#include "pagx/nodes/Composition.h"
Expand All @@ -47,6 +46,7 @@
#include "pagx/types/Padding.h"
#include "pagx/types/Rect.h"
#include "pagx/types/SelectorTypes.h"
#include "pagx/utils/Woff2FontGenerator.h"

namespace pagx {

Expand Down Expand Up @@ -85,17 +85,6 @@ Color LerpColor(const Color& a, const Color& b, float t);

std::string LayerTransformCSS(const Layer* layer);

/**
* HTML-local wrapper around pagx::BuildGroupMatrix that negates the `group->skew` angle so the
* resulting shear matches tgfx native rendering (VectorGroup::ApplySkew uses
* `DegreesToRadians(-skew)`). The shared pagx::BuildGroupMatrix follows the SVG matrix sign
* convention asserted by main's PAGXSVGTest.SVGExport_GroupSkew, so we cannot fix the sign at
* that layer without breaking the SVG / PPT exporters and their pinned test expectations. Use
* this wrapper everywhere the HTML exporter would have called BuildGroupMatrix on a Group node
* (path bake in flattenGroup, transform emission in writeGroup, etc.).
*/
Matrix BuildGroupMatrixForHTML(const Group* group);

const char* AlignmentToCSS(Alignment alignment);
const char* ArrangementToCSS(Arrangement arrangement);
std::string PaddingToCSS(const Padding& padding);
Expand Down
3 changes: 2 additions & 1 deletion src/pagx/html/HTMLWriterGroup.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
#include "pagx/nodes/Group.h"
#include "pagx/nodes/Repeater.h"
#include "pagx/nodes/Stroke.h"
#include "pagx/utils/ExporterUtils.h"
#include "pagx/utils/StringParser.h"

namespace pagx {
Expand All @@ -38,7 +39,7 @@ void HTMLWriter::writeGroup(HTMLBuilder& out, const Group* group, float alpha, b
if (guard.overflowed()) {
return;
}
Matrix gm = BuildGroupMatrixForHTML(group);
Matrix gm = BuildGroupMatrix(group);
if (!parentMatrix.isIdentity()) {
gm = parentMatrix * gm;
}
Expand Down
5 changes: 3 additions & 2 deletions src/pagx/html/HTMLWriterLayer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@
#include "pagx/nodes/TrimPath.h"
#include "pagx/svg/SVGPathParser.h"
#include "pagx/types/MergePathMode.h"
#include "pagx/utils/ExporterUtils.h"
#include "pagx/utils/StringParser.h"

namespace pagx {
Expand Down Expand Up @@ -521,7 +522,7 @@ void HTMLWriter::writeElements(HTMLBuilder& out, const std::vector<Element*>& el
// reads Text::renderPosition relative to the Group — not the enclosing Layer — so a
// flattened Group would drop its constraint offset from the span's top/left and the
// text would collapse onto the Layer's origin (app_icons Calendar "17" symptom).
bool groupHasTransform = !BuildGroupMatrixForHTML(group).isIdentity();
bool groupHasTransform = !BuildGroupMatrix(group).isIdentity();
// Only use the DOM wrapper (writeGroup) when the Group has a transform AND contains
// Text — the wrapper is needed so Text can resolve its renderPosition in Group space.
// Groups with alpha but no transform/text must use the flatten path so their geometry
Expand Down Expand Up @@ -650,7 +651,7 @@ void HTMLWriter::flattenGroup(HTMLBuilder& out, const Group* group, float alpha,
const TextBox* curTextBox, ElementDispatchState& state) {
ElementDispatchStateGuard stateGuard(state);
std::vector<GeoInfo> groupGeos;
Matrix gm = BuildGroupMatrixForHTML(group);
Matrix gm = BuildGroupMatrix(group);
// When a Group has alpha < 1, its Painters render with that alpha applied. In the
// flatten path, carry the group's alpha into every paintGeos/writeTextPath/
// writeTextModifier call so the fill-opacity matches the tgfx compositing result.
Expand Down
46 changes: 0 additions & 46 deletions src/pagx/html/HTMLWriterUtils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -476,52 +476,6 @@ std::string LayerTransformCSS(const Layer* layer) {
return MatrixTransformToCSS(m);
}

// HTML-local skew sign fix. Mirrors pagx::BuildGroupMatrix line-for-line except for one shear:
// the shear coefficient uses `tan(-group->skew)` so the result agrees with tgfx native rendering
// (VectorGroup::ApplySkew passes `DegreesToRadians(-skew)` into the shear). The shared
// pagx::BuildGroupMatrix uses the +skew sign because main's PAGXSVGTest.SVGExport_GroupSkew
// pinned that convention for SVG output, and the SVG/PPT exporters depend on it. Rather than
// flipping the shared helper (which would break those exporters and the pinned test) we keep
// the HTML exporter's path bake aligned with native by routing every BuildGroupMatrix call
// through this wrapper. Any change to the rest of BuildGroupMatrix must be mirrored here.
Matrix BuildGroupMatrixForHTML(const Group* group) {
auto renderPos = group->renderPosition();
bool hasAnchor = !FloatNearlyZero(group->anchor.x) || !FloatNearlyZero(group->anchor.y);
bool hasPosition = !FloatNearlyZero(renderPos.x) || !FloatNearlyZero(renderPos.y);
bool hasRotation = !FloatNearlyZero(group->rotation);
bool hasScale =
!FloatNearlyZero(group->scale.x - 1.0f) || !FloatNearlyZero(group->scale.y - 1.0f);
bool hasSkew = !FloatNearlyZero(group->skew);

if (!hasAnchor && !hasPosition && !hasRotation && !hasScale && !hasSkew) {
return {};
}

Matrix m = {};
if (hasAnchor) {
m = Matrix::Translate(-group->anchor.x, -group->anchor.y);
}
if (hasScale) {
m = Matrix::Scale(group->scale.x, group->scale.y) * m;
}
if (hasSkew) {
m = Matrix::Rotate(group->skewAxis) * m;
Matrix shear = {};
// Sign deliberately negated relative to pagx::BuildGroupMatrix; see function comment.
shear.c = std::tan(DegreesToRadians(-group->skew));
m = shear * m;
m = Matrix::Rotate(-group->skewAxis) * m;
}
if (hasRotation) {
m = Matrix::Rotate(group->rotation) * m;
}
if (hasPosition) {
m = Matrix::Translate(renderPos.x, renderPos.y) * m;
}

return m;
}

//==============================================================================
// Text & Font
//==============================================================================
Expand Down
Loading
Loading