2025-11-28 00:35:46 +09:00

170 lines
4.9 KiB
C++

// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
// ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
// PARTICULAR PURPOSE.
//
// Copyright (c) Microsoft Corporation. All rights reserved
//
// Contents: Custom layout, demonstrating usage of shaping and glyph
// results.
//
//----------------------------------------------------------------------------
#pragma once
#include "FlowSource.h"
#include "FlowSink.h"
#include "TextAnalysis.h"
class DECLSPEC_UUID("E304E995-6157-48ec-8D44-ACB308A210D0") FlowLayout
: public ComBase<
QiListSelf<FlowLayout,
QiList<IUnknown
> > >
{
// This custom layout processes layout in two stages.
//
// 1. Analyze the text, given the current font and size
// a. Bidirectional analysis
// b. Script analysis
// c. Number substitution analysis
// d. Shape glyphs
// e. Intersect run results
//
// 2. Fill the text to the given shape
// a. Pull next rect from flow source
// b. Fit as much text as will go in
// c. Push text to flow sink
public:
struct ClusterPosition
{
ClusterPosition()
: textPosition(),
runIndex(),
runEndPosition()
{ }
UINT32 textPosition; // Current text position
UINT32 runIndex; // Associated analysis run covering this position
UINT32 runEndPosition; // Text position where this run ends
};
public:
FlowLayout(IDWriteFactory* dwriteFactory)
: dwriteFactory_(SafeAcquire(dwriteFactory)),
fontFace_(),
numberSubstitution_(),
readingDirection_(DWRITE_READING_DIRECTION_LEFT_TO_RIGHT),
fontEmSize_(12),
maxSpaceWidth_(8),
isTextAnalysisComplete_(false)
{
}
~FlowLayout()
{
SafeRelease(&dwriteFactory_);
SafeRelease(&fontFace_);
SafeRelease(&numberSubstitution_);
}
STDMETHODIMP SetTextFormat(IDWriteTextFormat* textFormat);
STDMETHODIMP SetNumberSubstitution(IDWriteNumberSubstitution* numberSubstitution);
// Perform analysis on the given text, converting text to glyphs.
STDMETHODIMP AnalyzeText(
const wchar_t* text, // [textLength]
UINT32 textLength
);
// Reflow the text analysis into
STDMETHODIMP FlowText(
FlowLayoutSource* flowSource,
FlowLayoutSink* flowSink
);
protected:
STDMETHODIMP ShapeGlyphRuns(IDWriteTextAnalyzer* textAnalyzer);
STDMETHODIMP ShapeGlyphRun(
IDWriteTextAnalyzer* textAnalyzer,
UINT32 runIndex,
IN OUT UINT32& glyphStart
);
STDMETHODIMP FitText(
const ClusterPosition& clusterStart,
UINT32 textEnd,
float maxWidth,
OUT ClusterPosition* clusterEnd
);
STDMETHODIMP ProduceGlyphRuns(
FlowLayoutSink* flowSink,
const FlowLayoutSource::RectF& rect,
const ClusterPosition& clusterStart,
const ClusterPosition& clusterEnd
) const throw();
STDMETHODIMP ProduceJustifiedAdvances(
const FlowLayoutSource::RectF& rect,
const ClusterPosition& clusterStart,
const ClusterPosition& clusterEnd,
OUT std::vector<float>& justifiedAdvances
) const throw();
void ProduceBidiOrdering(
UINT32 spanStart,
UINT32 spanCount,
OUT UINT32* spanIndices // [spanCount]
) const throw();
void SetClusterPosition(
IN OUT ClusterPosition& cluster,
UINT32 textPosition
) const throw();
void AdvanceClusterPosition(
IN OUT ClusterPosition& cluster
) const throw();
UINT32 GetClusterGlyphStart(
const ClusterPosition& cluster
) const throw();
float GetClusterRangeWidth(
const ClusterPosition& clusterStart,
const ClusterPosition& clusterEnd
) const throw();
float GetClusterRangeWidth(
UINT32 glyphStart,
UINT32 glyphEnd,
const float* glyphAdvances // [glyphEnd]
) const throw();
protected:
IDWriteFactory* dwriteFactory_;
// Input information.
std::wstring text_;
wchar_t localeName_[LOCALE_NAME_MAX_LENGTH];
DWRITE_READING_DIRECTION readingDirection_;
IDWriteFontFace* fontFace_;
IDWriteNumberSubstitution* numberSubstitution_;
float fontEmSize_;
// Output text analysis results
std::vector<TextAnalysis::Run> runs_;
std::vector<DWRITE_LINE_BREAKPOINT> breakpoints_;
std::vector<DWRITE_GLYPH_OFFSET> glyphOffsets_;
std::vector<UINT16> glyphClusters_;
std::vector<UINT16> glyphIndices_;
std::vector<float> glyphAdvances_;
float maxSpaceWidth_; // maximum stretch of space allowed for justification
bool isTextAnalysisComplete_; // text analysis was done.
};