Add initial directwrite to svg conversion.
This commit is contained in:
parent
2c825adc1d
commit
b7f75f903e
15 changed files with 571 additions and 7 deletions
|
@ -27,4 +27,5 @@ target_include_directories(${PLUGIN_NAME} PUBLIC
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/visuals
|
${CMAKE_CURRENT_SOURCE_DIR}/visuals
|
||||||
)
|
)
|
||||||
target_link_libraries(${PLUGIN_NAME} PUBLIC core visual_elements ntk_math)
|
target_link_libraries(${PLUGIN_NAME} PUBLIC core visual_elements ntk_math)
|
||||||
set_property(TARGET ${PLUGIN_NAME} PROPERTY FOLDER plugins)
|
set_property(TARGET ${PLUGIN_NAME} PROPERTY FOLDER plugins)
|
||||||
|
set_target_properties( ${PLUGIN_NAME} PROPERTIES WINDOWS_EXPORT_ALL_SYMBOLS ON )
|
|
@ -13,7 +13,7 @@
|
||||||
|
|
||||||
TEST_CASE(TestBlochSphereNode, "quantum_computing")
|
TEST_CASE(TestBlochSphereNode, "quantum_computing")
|
||||||
{
|
{
|
||||||
auto node = std::make_unique<BlochSphereNode>();
|
auto node = std::make_unique<BlochSphereNode>(DiscretePoint(0.5, 0.5));
|
||||||
|
|
||||||
Qubit state({ 1.0, 0.0 }, { 0.0, 0.0 });
|
Qubit state({ 1.0, 0.0 }, { 0.0, 0.0 });
|
||||||
|
|
||||||
|
|
|
@ -8,6 +8,12 @@ list(APPEND fonts_LIB_INCLUDES
|
||||||
TrueTypeFont.cpp
|
TrueTypeFont.cpp
|
||||||
FontsManager.cpp
|
FontsManager.cpp
|
||||||
FontGlyph.cpp
|
FontGlyph.cpp
|
||||||
|
FontReader.h
|
||||||
|
TrueTypeFont.h
|
||||||
|
FontsManager.h
|
||||||
|
FontGlyph.h
|
||||||
|
IFont.h
|
||||||
|
IFontEngine.h
|
||||||
)
|
)
|
||||||
|
|
||||||
if(UNIX)
|
if(UNIX)
|
||||||
|
@ -24,15 +30,26 @@ if(UNIX)
|
||||||
else()
|
else()
|
||||||
message(STATUS "Freetype not found - skipping support")
|
message(STATUS "Freetype not found - skipping support")
|
||||||
endif()
|
endif()
|
||||||
|
else()
|
||||||
|
list(APPEND fonts_LIB_INCLUDES
|
||||||
|
directx/DirectWriteFontEngine.h
|
||||||
|
directx/DirectWriteHelpers.h
|
||||||
|
directx/DirectWriteFontEngine.cpp
|
||||||
|
directx/DirectWriteHelpers.cpp
|
||||||
|
)
|
||||||
|
list(APPEND fonts_LIB_DEPENDS
|
||||||
|
Dwrite.lib D2d1.lib uuid.lib
|
||||||
|
)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
add_library(${MODULE_NAME} SHARED ${fonts_LIB_INCLUDES})
|
add_library(${MODULE_NAME} SHARED ${fonts_LIB_INCLUDES})
|
||||||
|
|
||||||
target_include_directories(${MODULE_NAME} PUBLIC
|
target_include_directories(${MODULE_NAME} PUBLIC
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}
|
${CMAKE_CURRENT_SOURCE_DIR}
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/directx
|
||||||
)
|
)
|
||||||
|
|
||||||
target_link_libraries(${MODULE_NAME} PUBLIC core image ${fonts_LIB_DEPENDS})
|
target_link_libraries(${MODULE_NAME} PUBLIC core geometry image ${fonts_LIB_DEPENDS})
|
||||||
|
|
||||||
target_compile_definitions(${MODULE_NAME} PRIVATE ${DEFINES})
|
target_compile_definitions(${MODULE_NAME} PRIVATE ${DEFINES})
|
||||||
set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER src)
|
set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER src)
|
||||||
|
|
|
@ -1,5 +1,43 @@
|
||||||
#include "FontGlyph.h"
|
#include "FontGlyph.h"
|
||||||
|
|
||||||
|
void GlyphRunOutlines::addToFeature(const Point& point)
|
||||||
|
{
|
||||||
|
mFeatures[mFeatures.size() - 1].mPoints.push_back(point);
|
||||||
|
}
|
||||||
|
|
||||||
|
void GlyphRunOutlines::startFeature(const Point& point, bool isFilled)
|
||||||
|
{
|
||||||
|
GlyphRunOutline feature;
|
||||||
|
feature.mFilled = isFilled;
|
||||||
|
feature.mPoints.push_back(point);
|
||||||
|
mFeatures.push_back(feature);
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::vector<GlyphRunOutline> GlyphRunOutlines::getFeatures() const
|
||||||
|
{
|
||||||
|
return mFeatures;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string GlyphRunOutlines::toPostScriptPath()
|
||||||
|
{
|
||||||
|
std::string path;
|
||||||
|
for (const auto& feature : mFeatures)
|
||||||
|
{
|
||||||
|
if (feature.mPoints.empty())
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
auto last_point = feature.mPoints[0];
|
||||||
|
path += "M" + std::to_string(last_point.getX()) + " " + std::to_string(last_point.getY()) + " ";
|
||||||
|
for (std::size_t idx = 1; idx < feature.mPoints.size(); idx++)
|
||||||
|
{
|
||||||
|
path += "L" + std::to_string(feature.mPoints[idx].getX()) + " " + std::to_string(feature.mPoints[idx].getY()) + " ";
|
||||||
|
}
|
||||||
|
path += "z ";
|
||||||
|
}
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
|
||||||
FontGlyph::FontGlyph(unsigned width, unsigned height, int bearingX, int bearingY,
|
FontGlyph::FontGlyph(unsigned width, unsigned height, int bearingX, int bearingY,
|
||||||
int advanceX, std::unique_ptr<Image<unsigned char> > image)
|
int advanceX, std::unique_ptr<Image<unsigned char> > image)
|
||||||
: mImage(std::move(image)),
|
: mImage(std::move(image)),
|
||||||
|
|
|
@ -1,9 +1,31 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <memory>
|
#include "Point.h"
|
||||||
|
|
||||||
#include "Image.h"
|
#include "Image.h"
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
#include <vector>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
struct GlyphRunOutline
|
||||||
|
{
|
||||||
|
bool mFilled{ true };
|
||||||
|
std::vector<Point> mPoints;
|
||||||
|
};
|
||||||
|
|
||||||
|
class GlyphRunOutlines
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
void addToFeature(const Point& point);
|
||||||
|
void startFeature(const Point& point, bool isFilled);
|
||||||
|
|
||||||
|
const std::vector<GlyphRunOutline> getFeatures() const;
|
||||||
|
|
||||||
|
std::string toPostScriptPath();
|
||||||
|
private:
|
||||||
|
std::vector<GlyphRunOutline> mFeatures;
|
||||||
|
};
|
||||||
|
|
||||||
class FontGlyph
|
class FontGlyph
|
||||||
{
|
{
|
||||||
|
|
||||||
|
|
54
src/fonts/directx/DirectWriteFontEngine.cpp
Normal file
54
src/fonts/directx/DirectWriteFontEngine.cpp
Normal file
|
@ -0,0 +1,54 @@
|
||||||
|
#include "DirectWriteFontEngine.h"
|
||||||
|
|
||||||
|
#include "FontGlyph.h"
|
||||||
|
#include "StringUtils.h"
|
||||||
|
|
||||||
|
#include "DirectWriteHelpers.h"
|
||||||
|
|
||||||
|
#include <dwrite.h>
|
||||||
|
|
||||||
|
void DirectWriteFontEngine::initialize()
|
||||||
|
{
|
||||||
|
mIsValid = SUCCEEDED(::DWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED, __uuidof(IDWriteFactory), &mDWriteFactory));
|
||||||
|
|
||||||
|
loadFontFaceFromName("Verdana", 16);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DirectWriteFontEngine::initializeOffScreenRenderer()
|
||||||
|
{
|
||||||
|
if (mOffScreenRenderer)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
auto pInterface = OffScreenTextRenderer::Create();
|
||||||
|
pInterface->QueryInterface(IID_IOffScreenTextRenderer, &mOffScreenRenderer);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DirectWriteFontEngine::loadFontFaceFromName(const std::string& fontName, int penSize)
|
||||||
|
{
|
||||||
|
mDWriteFactory->CreateTextFormat(StringUtils::convert(fontName).c_str(), nullptr, DWRITE_FONT_WEIGHT_NORMAL, DWRITE_FONT_STYLE_NORMAL, DWRITE_FONT_STRETCH_NORMAL,
|
||||||
|
penSize, L"en-us", &mTextFormat);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::unique_ptr<FontGlyph> DirectWriteFontEngine::loadGlyph(uint32_t charCode)
|
||||||
|
{
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::unique_ptr<GlyphRunOutlines> DirectWriteFontEngine::getGlyphRunOutlines(const std::vector<uint32_t>& charCodes)
|
||||||
|
{
|
||||||
|
initializeOffScreenRenderer();
|
||||||
|
|
||||||
|
std::wstring text;
|
||||||
|
for (auto code : charCodes)
|
||||||
|
{
|
||||||
|
text.push_back(code);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto hr = mDWriteFactory->CreateTextLayout(text.c_str(), text.size(), mTextFormat.Get(), 50.0, 50.0, &mTextLayout);
|
||||||
|
|
||||||
|
mTextLayout->Draw(nullptr, mOffScreenRenderer.Get(), 0.0, 0.0);
|
||||||
|
|
||||||
|
return mOffScreenRenderer->getGlypyRunOutline();
|
||||||
|
}
|
||||||
|
|
38
src/fonts/directx/DirectWriteFontEngine.h
Normal file
38
src/fonts/directx/DirectWriteFontEngine.h
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "IFontEngine.h"
|
||||||
|
#include "FontGlyph.h"
|
||||||
|
|
||||||
|
#include <wrl.h>
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
class GlyphOutlineGeometrySink;
|
||||||
|
class OffScreenTextRenderer;
|
||||||
|
|
||||||
|
struct IDWriteFactory;
|
||||||
|
struct IDWriteTextFormat;
|
||||||
|
struct IDWriteTextLayout;
|
||||||
|
|
||||||
|
class DirectWriteFontEngine : public IFontEngine
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
void initialize() override;
|
||||||
|
|
||||||
|
void loadFontFace(const std::filesystem::path& fontFile, int penSize = 16) override {};
|
||||||
|
|
||||||
|
void loadFontFaceFromName(const std::string& fontName, int penSize = 16);
|
||||||
|
|
||||||
|
std::unique_ptr<FontGlyph> loadGlyph(uint32_t charCode) override;
|
||||||
|
|
||||||
|
std::unique_ptr<GlyphRunOutlines> getGlyphRunOutlines(const std::vector<uint32_t>& charCodes);
|
||||||
|
|
||||||
|
private:
|
||||||
|
void initializeOffScreenRenderer();
|
||||||
|
|
||||||
|
bool mIsValid{ false };
|
||||||
|
Microsoft::WRL::ComPtr<IDWriteFactory> mDWriteFactory;
|
||||||
|
Microsoft::WRL::ComPtr<IDWriteTextFormat> mTextFormat;
|
||||||
|
Microsoft::WRL::ComPtr<IDWriteTextLayout> mTextLayout;
|
||||||
|
Microsoft::WRL::ComPtr<OffScreenTextRenderer> mOffScreenRenderer;
|
||||||
|
};
|
235
src/fonts/directx/DirectWriteHelpers.cpp
Normal file
235
src/fonts/directx/DirectWriteHelpers.cpp
Normal file
|
@ -0,0 +1,235 @@
|
||||||
|
#include "DirectWriteHelpers.h"
|
||||||
|
|
||||||
|
#include "FileLogger.h"
|
||||||
|
|
||||||
|
#include <wrl.h>
|
||||||
|
|
||||||
|
GlyphOutlineGeometrySink::GlyphOutlineGeometrySink()
|
||||||
|
: mGlyphRunOutline(std::make_unique<GlyphRunOutlines>())
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
IUnknown* GlyphOutlineGeometrySink::Create()
|
||||||
|
{
|
||||||
|
return static_cast<IGlyphOutlineGeometrySink*>(new GlyphOutlineGeometrySink);
|
||||||
|
}
|
||||||
|
|
||||||
|
HRESULT __stdcall GlyphOutlineGeometrySink::QueryInterface(const IID& iid, void** ppv)
|
||||||
|
{
|
||||||
|
if (IsEqualIID(iid, __uuidof(IUnknown)))
|
||||||
|
{
|
||||||
|
*ppv = static_cast<IGlyphOutlineGeometrySink*>(this);
|
||||||
|
}
|
||||||
|
else if (IsEqualIID(iid, IID_ID2D1SimplifiedGeometrySink))
|
||||||
|
{
|
||||||
|
*ppv = static_cast<IGlyphOutlineGeometrySink*>(this);
|
||||||
|
}
|
||||||
|
else if (IsEqualIID(iid, IID_IGlyphOutlineGeometrySink))
|
||||||
|
{
|
||||||
|
*ppv = static_cast<IGlyphOutlineGeometrySink*>(this);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
*ppv = nullptr;
|
||||||
|
return E_NOINTERFACE;
|
||||||
|
}
|
||||||
|
reinterpret_cast<IUnknown*>(*ppv)->AddRef();
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
ULONG __stdcall GlyphOutlineGeometrySink::AddRef()
|
||||||
|
{
|
||||||
|
return ::InterlockedIncrement(&mRefCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
ULONG __stdcall GlyphOutlineGeometrySink::Release()
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
if (::InterlockedDecrement(&mRefCount) == 0)
|
||||||
|
{
|
||||||
|
delete this;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return mRefCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
void __stdcall GlyphOutlineGeometrySink::SetFillMode(D2D1_FILL_MODE fillMode)
|
||||||
|
{
|
||||||
|
MLOG_INFO("SetFillMode: " << bool(fillMode == D2D1_FILL_MODE_ALTERNATE));
|
||||||
|
}
|
||||||
|
|
||||||
|
void __stdcall GlyphOutlineGeometrySink::SetSegmentFlags(D2D1_PATH_SEGMENT vertexFlags)
|
||||||
|
{
|
||||||
|
MLOG_INFO("SetSegmentFlags");
|
||||||
|
if (vertexFlags == D2D1_PATH_SEGMENT_NONE)
|
||||||
|
{
|
||||||
|
MLOG_INFO("D2D1_PATH_SEGMENT_NONE");
|
||||||
|
}
|
||||||
|
else if (vertexFlags == D2D1_PATH_SEGMENT_FORCE_UNSTROKED)
|
||||||
|
{
|
||||||
|
MLOG_INFO("D2D1_PATH_SEGMENT_FORCE_UNSTROKED");
|
||||||
|
}
|
||||||
|
else if (vertexFlags == D2D1_PATH_SEGMENT_FORCE_ROUND_LINE_JOIN)
|
||||||
|
{
|
||||||
|
MLOG_INFO("D2D1_PATH_SEGMENT_FORCE_ROUND_LINE_JOIN");
|
||||||
|
}
|
||||||
|
else if (vertexFlags == D2D1_PATH_SEGMENT_FORCE_DWORD)
|
||||||
|
{
|
||||||
|
MLOG_INFO("D2D1_PATH_SEGMENT_FORCE_DWORD");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
MLOG_INFO("UKNOWN");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void __stdcall GlyphOutlineGeometrySink::BeginFigure(D2D1_POINT_2F startPoint, D2D1_FIGURE_BEGIN figureBegin)
|
||||||
|
{
|
||||||
|
MLOG_INFO("BeginFigure, is filled: " << bool(figureBegin == D2D1_FIGURE_BEGIN_FILLED));
|
||||||
|
mGlyphRunOutline->startFeature(Point(startPoint.x, startPoint.y), figureBegin == D2D1_FIGURE_BEGIN_FILLED);
|
||||||
|
}
|
||||||
|
|
||||||
|
void __stdcall GlyphOutlineGeometrySink::AddLines(_In_reads_(pointsCount) CONST D2D1_POINT_2F* points, UINT32 pointsCount)
|
||||||
|
{
|
||||||
|
MLOG_INFO("AddLines");
|
||||||
|
for (UINT32 idx = 0; idx < pointsCount; idx++)
|
||||||
|
{
|
||||||
|
auto point = points[idx];
|
||||||
|
MLOG_INFO("Adding point: " << point.x << " " << point.y);
|
||||||
|
mGlyphRunOutline->addToFeature(Point(point.x, point.y));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void __stdcall GlyphOutlineGeometrySink::AddBeziers(_In_reads_(beziersCount) CONST D2D1_BEZIER_SEGMENT* beziers, UINT32 beziersCount)
|
||||||
|
{
|
||||||
|
MLOG_INFO("AddBeziers");
|
||||||
|
}
|
||||||
|
|
||||||
|
void __stdcall GlyphOutlineGeometrySink::EndFigure(D2D1_FIGURE_END figureEnd)
|
||||||
|
{
|
||||||
|
MLOG_INFO("EndFigure");
|
||||||
|
}
|
||||||
|
|
||||||
|
HRESULT __stdcall GlyphOutlineGeometrySink::Close()
|
||||||
|
{
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::unique_ptr<GlyphRunOutlines> GlyphOutlineGeometrySink::getGlypyRunOutline()
|
||||||
|
{
|
||||||
|
return std::move(mGlyphRunOutline);
|
||||||
|
}
|
||||||
|
|
||||||
|
IUnknown* OffScreenTextRenderer::Create()
|
||||||
|
{
|
||||||
|
return static_cast<IOffScreenTextRenderer*>(new OffScreenTextRenderer);
|
||||||
|
}
|
||||||
|
|
||||||
|
HRESULT __stdcall OffScreenTextRenderer::QueryInterface(const IID& iid, void** ppv)
|
||||||
|
{
|
||||||
|
if (IsEqualIID(iid, __uuidof(IUnknown)))
|
||||||
|
{
|
||||||
|
*ppv = static_cast<IOffScreenTextRenderer*>(this);
|
||||||
|
}
|
||||||
|
else if (IsEqualIID(iid, __uuidof(IDWritePixelSnapping)))
|
||||||
|
{
|
||||||
|
*ppv = static_cast<IOffScreenTextRenderer*>(this);
|
||||||
|
}
|
||||||
|
else if (IsEqualIID(iid, __uuidof(IDWriteTextRenderer)))
|
||||||
|
{
|
||||||
|
*ppv = static_cast<IOffScreenTextRenderer*>(this);
|
||||||
|
}
|
||||||
|
else if (IsEqualIID(iid, IID_IOffScreenTextRenderer))
|
||||||
|
{
|
||||||
|
*ppv = static_cast<IOffScreenTextRenderer*>(this);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
*ppv = nullptr;
|
||||||
|
return E_NOINTERFACE;
|
||||||
|
}
|
||||||
|
reinterpret_cast<IUnknown*>(*ppv)->AddRef();
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
ULONG __stdcall OffScreenTextRenderer::AddRef()
|
||||||
|
{
|
||||||
|
return ::InterlockedIncrement(&mRefCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
ULONG __stdcall OffScreenTextRenderer::Release()
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
if (::InterlockedDecrement(&mRefCount) == 0)
|
||||||
|
{
|
||||||
|
delete this;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return mRefCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
HRESULT __stdcall OffScreenTextRenderer::DrawGlyphRun(_In_opt_ void* clientDrawingContext, FLOAT baselineOriginX, FLOAT baselineOriginY, DWRITE_MEASURING_MODE measuringMode,
|
||||||
|
_In_ DWRITE_GLYPH_RUN const* glyphRun, _In_ DWRITE_GLYPH_RUN_DESCRIPTION const* glyphRunDescription, _In_opt_ IUnknown* clientDrawingEffect)
|
||||||
|
{
|
||||||
|
auto pInterface = GlyphOutlineGeometrySink::Create();
|
||||||
|
Microsoft::WRL::ComPtr<GlyphOutlineGeometrySink> sink;
|
||||||
|
pInterface->QueryInterface(IID_IGlyphOutlineGeometrySink, &sink);
|
||||||
|
|
||||||
|
auto hr = glyphRun->fontFace->GetGlyphRunOutline(
|
||||||
|
glyphRun->fontEmSize,
|
||||||
|
glyphRun->glyphIndices,
|
||||||
|
glyphRun->glyphAdvances,
|
||||||
|
glyphRun->glyphOffsets,
|
||||||
|
glyphRun->glyphCount,
|
||||||
|
glyphRun->isSideways,
|
||||||
|
glyphRun->bidiLevel % 2,
|
||||||
|
sink.Get()
|
||||||
|
);
|
||||||
|
sink->Close();
|
||||||
|
|
||||||
|
mGlyphRunOutline = sink->getGlypyRunOutline();
|
||||||
|
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
HRESULT __stdcall OffScreenTextRenderer::DrawUnderline(_In_opt_ void* clientDrawingContext, FLOAT baselineOriginX, FLOAT baselineOriginY, _In_ DWRITE_UNDERLINE const* underline,
|
||||||
|
_In_opt_ IUnknown* clientDrawingEffect)
|
||||||
|
{
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
HRESULT __stdcall OffScreenTextRenderer::DrawStrikethrough(_In_opt_ void* clientDrawingContext, FLOAT baselineOriginX, FLOAT baselineOriginY, _In_ DWRITE_STRIKETHROUGH const* strikethrough,
|
||||||
|
_In_opt_ IUnknown* clientDrawingEffect)
|
||||||
|
{
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
HRESULT __stdcall OffScreenTextRenderer::DrawInlineObject(_In_opt_ void* clientDrawingContext, FLOAT originX, FLOAT originY, _In_ IDWriteInlineObject* inlineObject,
|
||||||
|
BOOL isSideways, BOOL isRightToLeft, _In_opt_ IUnknown* clientDrawingEffect)
|
||||||
|
{
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
HRESULT __stdcall OffScreenTextRenderer::IsPixelSnappingDisabled(_In_opt_ void* clientDrawingContext, _Out_ BOOL* isDisabled)
|
||||||
|
{
|
||||||
|
*isDisabled = FALSE;
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
HRESULT __stdcall OffScreenTextRenderer::GetCurrentTransform(_In_opt_ void* clientDrawingContext, _Out_ DWRITE_MATRIX* transform)
|
||||||
|
{
|
||||||
|
*transform = DWRITE_MATRIX(1.0, 0.0, 0.0, 1.0, 0.0, 0.0);
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
HRESULT __stdcall OffScreenTextRenderer::GetPixelsPerDip(_In_opt_ void* clientDrawingContext, _Out_ FLOAT* pixelsPerDip)
|
||||||
|
{
|
||||||
|
*pixelsPerDip = 1.0;
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::unique_ptr<GlyphRunOutlines> OffScreenTextRenderer::getGlypyRunOutline()
|
||||||
|
{
|
||||||
|
return std::move(mGlyphRunOutline);
|
||||||
|
}
|
90
src/fonts/directx/DirectWriteHelpers.h
Normal file
90
src/fonts/directx/DirectWriteHelpers.h
Normal file
|
@ -0,0 +1,90 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "FontGlyph.h"
|
||||||
|
|
||||||
|
#include <d2d1_1.h>
|
||||||
|
#include <dwrite.h>
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
static const IID IID_IGlyphOutlineGeometrySink = { 0xaaf6ab8d, 0xd6cf, 0x4a3b, { 0xa6, 0x7a, 0x12, 0xf1, 0x42, 0xe0, 0x6b, 0xb9 } };
|
||||||
|
class IGlyphOutlineGeometrySink : public IDWriteGeometrySink
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
virtual std::unique_ptr<GlyphRunOutlines> getGlypyRunOutline() = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
class GlyphOutlineGeometrySink :public IGlyphOutlineGeometrySink
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
GlyphOutlineGeometrySink();
|
||||||
|
|
||||||
|
// IUnknown
|
||||||
|
virtual HRESULT __stdcall QueryInterface(const IID& iid, void** ppv);
|
||||||
|
virtual ULONG __stdcall AddRef();
|
||||||
|
virtual ULONG __stdcall Release();
|
||||||
|
|
||||||
|
static IUnknown* Create();
|
||||||
|
|
||||||
|
// IDWriteGeometrySink aka ID2D1SimplifiedGeometrySink
|
||||||
|
STDMETHOD_(void, SetFillMode)(D2D1_FILL_MODE fillMode);
|
||||||
|
|
||||||
|
STDMETHOD_(void, SetSegmentFlags)(D2D1_PATH_SEGMENT vertexFlags);
|
||||||
|
|
||||||
|
STDMETHOD_(void, BeginFigure)(D2D1_POINT_2F startPoint, D2D1_FIGURE_BEGIN figureBegin);
|
||||||
|
|
||||||
|
STDMETHOD_(void, AddLines)(_In_reads_(pointsCount) CONST D2D1_POINT_2F* points, UINT32 pointsCount);
|
||||||
|
|
||||||
|
STDMETHOD_(void, AddBeziers)(_In_reads_(beziersCount) CONST D2D1_BEZIER_SEGMENT* beziers, UINT32 beziersCount);
|
||||||
|
|
||||||
|
STDMETHOD_(void, EndFigure)(D2D1_FIGURE_END figureEnd);
|
||||||
|
|
||||||
|
STDMETHOD(Close)();
|
||||||
|
|
||||||
|
// IGlyphOutlineGeometrySink
|
||||||
|
std::unique_ptr<GlyphRunOutlines> getGlypyRunOutline() override;
|
||||||
|
private:
|
||||||
|
std::unique_ptr<GlyphRunOutlines> mGlyphRunOutline;
|
||||||
|
long mRefCount{ 0 };
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
static const IID IID_IOffScreenTextRenderer = { 0xa43b0c49, 0x6080, 0x4731, { 0xa8, 0x72, 0x61, 0x50, 0x47, 0x3, 0x78, 0x10 } };
|
||||||
|
class IOffScreenTextRenderer : public IDWriteTextRenderer
|
||||||
|
{
|
||||||
|
virtual std::unique_ptr<GlyphRunOutlines> getGlypyRunOutline() = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
class OffScreenTextRenderer :public IOffScreenTextRenderer
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
// IUnknown
|
||||||
|
virtual HRESULT __stdcall QueryInterface(const IID& iid, void** ppv);
|
||||||
|
virtual ULONG __stdcall AddRef();
|
||||||
|
virtual ULONG __stdcall Release();
|
||||||
|
|
||||||
|
static IUnknown* Create();
|
||||||
|
|
||||||
|
STDMETHOD(DrawGlyphRun)(_In_opt_ void* clientDrawingContext, FLOAT baselineOriginX, FLOAT baselineOriginY, DWRITE_MEASURING_MODE measuringMode,
|
||||||
|
_In_ DWRITE_GLYPH_RUN const* glyphRun, _In_ DWRITE_GLYPH_RUN_DESCRIPTION const* glyphRunDescription, _In_opt_ IUnknown* clientDrawingEffect);
|
||||||
|
|
||||||
|
STDMETHOD(DrawUnderline)(_In_opt_ void* clientDrawingContext, FLOAT baselineOriginX, FLOAT baselineOriginY, _In_ DWRITE_UNDERLINE const* underline,
|
||||||
|
_In_opt_ IUnknown* clientDrawingEffect);
|
||||||
|
|
||||||
|
STDMETHOD(DrawStrikethrough)(_In_opt_ void* clientDrawingContext, FLOAT baselineOriginX, FLOAT baselineOriginY, _In_ DWRITE_STRIKETHROUGH const* strikethrough,
|
||||||
|
_In_opt_ IUnknown* clientDrawingEffect);
|
||||||
|
|
||||||
|
STDMETHOD(DrawInlineObject)(_In_opt_ void* clientDrawingContext, FLOAT originX, FLOAT originY, _In_ IDWriteInlineObject* inlineObject,
|
||||||
|
BOOL isSideways, BOOL isRightToLeft, _In_opt_ IUnknown* clientDrawingEffect);
|
||||||
|
|
||||||
|
STDMETHOD(IsPixelSnappingDisabled)(_In_opt_ void* clientDrawingContext, _Out_ BOOL* isDisabled);
|
||||||
|
|
||||||
|
STDMETHOD(GetCurrentTransform)(_In_opt_ void* clientDrawingContext, _Out_ DWRITE_MATRIX* transform);
|
||||||
|
|
||||||
|
STDMETHOD(GetPixelsPerDip)(_In_opt_ void* clientDrawingContext, _Out_ FLOAT* pixelsPerDip);
|
||||||
|
|
||||||
|
std::unique_ptr<GlyphRunOutlines> getGlypyRunOutline() override;
|
||||||
|
private:
|
||||||
|
std::unique_ptr<GlyphRunOutlines> mGlyphRunOutline;
|
||||||
|
long mRefCount{ 0 };
|
||||||
|
};
|
|
@ -17,7 +17,7 @@ SvgDocument::SvgDocument()
|
||||||
setRoot(std::move(root));
|
setRoot(std::move(root));
|
||||||
}
|
}
|
||||||
|
|
||||||
void SvgDocument::setViewBox(unsigned x, unsigned y, unsigned w, unsigned h)
|
void SvgDocument::setViewBox(double x, double y, double w, double h)
|
||||||
{
|
{
|
||||||
auto viewbox = std::make_unique<XmlAttribute>("viewBox");
|
auto viewbox = std::make_unique<XmlAttribute>("viewBox");
|
||||||
std::stringstream sstr;
|
std::stringstream sstr;
|
||||||
|
|
|
@ -6,5 +6,5 @@ class SvgDocument : public XmlDocument
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
SvgDocument();
|
SvgDocument();
|
||||||
void setViewBox(unsigned x, unsigned y, unsigned w, unsigned h);
|
void setViewBox(double x, double y, double w, double h);
|
||||||
};
|
};
|
||||||
|
|
|
@ -104,3 +104,23 @@ void SvgPolyline::setPoints(const std::vector<DiscretePoint>& locs)
|
||||||
addAttribute(std::move(points));
|
addAttribute(std::move(points));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
SvgPath::SvgPath()
|
||||||
|
: SvgShapeElement("path")
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void SvgPath::setPath(const std::string& mPath)
|
||||||
|
{
|
||||||
|
auto path = std::make_unique<XmlAttribute>("d");
|
||||||
|
path->setValue(mPath);
|
||||||
|
addAttribute(std::move(path));
|
||||||
|
}
|
||||||
|
|
||||||
|
void SvgPath::setFillRule(const std::string& fillRule)
|
||||||
|
{
|
||||||
|
auto rule = std::make_unique<XmlAttribute>("fill-rule");
|
||||||
|
rule->setValue(fillRule);
|
||||||
|
addAttribute(std::move(rule));
|
||||||
|
}
|
||||||
|
|
|
@ -42,3 +42,12 @@ public:
|
||||||
|
|
||||||
void setPoints(const std::vector<DiscretePoint>& loc);
|
void setPoints(const std::vector<DiscretePoint>& loc);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class SvgPath : public SvgShapeElement
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
SvgPath();
|
||||||
|
|
||||||
|
void setPath(const std::string& mPath);
|
||||||
|
void setFillRule(const std::string& fillRule);
|
||||||
|
};
|
||||||
|
|
|
@ -7,6 +7,10 @@ if(UNIX)
|
||||||
fonts/TestFreeTypeFontEngine.cpp
|
fonts/TestFreeTypeFontEngine.cpp
|
||||||
)
|
)
|
||||||
endif()
|
endif()
|
||||||
|
else()
|
||||||
|
set(PLATFORM_UNIT_TEST_FILES
|
||||||
|
fonts/TestDirectWriteFontEngine.cpp
|
||||||
|
)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
|
||||||
|
|
36
test/fonts/TestDirectWriteFontEngine.cpp
Normal file
36
test/fonts/TestDirectWriteFontEngine.cpp
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
#include "TestFramework.h"
|
||||||
|
#include "TestUtils.h"
|
||||||
|
|
||||||
|
#include "DirectWriteHelpers.h"
|
||||||
|
#include "DirectWriteFontEngine.h"
|
||||||
|
#include "FileLogger.h"
|
||||||
|
|
||||||
|
#include "SvgDocument.h"
|
||||||
|
#include "SvgWriter.h"
|
||||||
|
#include "SvgShapeElements.h"
|
||||||
|
#include "File.h"
|
||||||
|
|
||||||
|
TEST_CASE(TestDirectWriteFontEngine, "fonts")
|
||||||
|
{
|
||||||
|
DirectWriteFontEngine font_engine;
|
||||||
|
font_engine.initialize();
|
||||||
|
|
||||||
|
auto glyph_run_outlines = font_engine.getGlyphRunOutlines({ 66 });
|
||||||
|
auto path = glyph_run_outlines->toPostScriptPath();
|
||||||
|
|
||||||
|
auto doc = std::make_unique<SvgDocument>();
|
||||||
|
|
||||||
|
auto element = std::make_unique<SvgPath>();
|
||||||
|
element->setPath(path);
|
||||||
|
element->setFillRule("evenodd");
|
||||||
|
|
||||||
|
doc->getRoot()->addChild(std::move(element));
|
||||||
|
doc->setViewBox(-20.0, -20.0, 40.0, 40.0);
|
||||||
|
|
||||||
|
auto writer = std::make_unique<SvgWriter>();
|
||||||
|
auto doc_string = writer->toString(doc.get());
|
||||||
|
|
||||||
|
File file(TestUtils::getTestOutputDir(__FILE__) / "out.svg");
|
||||||
|
file.writeText(doc_string);
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in a new issue