927 lines
29 KiB
C
927 lines
29 KiB
C
/*
|
|
* Copyright 2012, 2014-2021 Nikolay Sivov for CodeWeavers
|
|
*
|
|
* This library is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
* License as published by the Free Software Foundation; either
|
|
* version 2.1 of the License, or (at your option) any later version.
|
|
*
|
|
* This library is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* Lesser General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
* License along with this library; if not, write to the Free Software
|
|
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
|
*/
|
|
|
|
#define COBJMACROS
|
|
|
|
#include "dwrite_private.h"
|
|
|
|
#include "wine/debug.h"
|
|
|
|
WINE_DEFAULT_DEBUG_CHANNEL(dwrite);
|
|
|
|
struct dwrite_trimmingsign
|
|
{
|
|
IDWriteInlineObject IDWriteInlineObject_iface;
|
|
LONG refcount;
|
|
|
|
IDWriteTextLayout *layout;
|
|
};
|
|
|
|
static inline struct dwrite_trimmingsign *impl_from_IDWriteInlineObject(IDWriteInlineObject *iface)
|
|
{
|
|
return CONTAINING_RECORD(iface, struct dwrite_trimmingsign, IDWriteInlineObject_iface);
|
|
}
|
|
|
|
void release_format_data(struct dwrite_textformat_data *data)
|
|
{
|
|
if (data->collection)
|
|
IDWriteFontCollection_Release(data->collection);
|
|
if (data->fallback)
|
|
IDWriteFontFallback_Release(data->fallback);
|
|
if (data->trimmingsign)
|
|
IDWriteInlineObject_Release(data->trimmingsign);
|
|
free(data->family_name);
|
|
free(data->locale);
|
|
free(data->axis_values);
|
|
}
|
|
|
|
static inline struct dwrite_textformat *impl_from_IDWriteTextFormat3(IDWriteTextFormat3 *iface)
|
|
{
|
|
return CONTAINING_RECORD(iface, struct dwrite_textformat, IDWriteTextFormat3_iface);
|
|
}
|
|
|
|
HRESULT format_set_textalignment(struct dwrite_textformat_data *format, DWRITE_TEXT_ALIGNMENT alignment,
|
|
BOOL *changed)
|
|
{
|
|
if ((UINT32)alignment > DWRITE_TEXT_ALIGNMENT_JUSTIFIED)
|
|
return E_INVALIDARG;
|
|
if (changed) *changed = format->textalignment != alignment;
|
|
format->textalignment = alignment;
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT format_set_paralignment(struct dwrite_textformat_data *format, DWRITE_PARAGRAPH_ALIGNMENT alignment, BOOL *changed)
|
|
{
|
|
if ((UINT32)alignment > DWRITE_PARAGRAPH_ALIGNMENT_CENTER)
|
|
return E_INVALIDARG;
|
|
if (changed) *changed = format->paralign != alignment;
|
|
format->paralign = alignment;
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT format_set_readingdirection(struct dwrite_textformat_data *format, DWRITE_READING_DIRECTION direction, BOOL *changed)
|
|
{
|
|
if ((UINT32)direction > DWRITE_READING_DIRECTION_BOTTOM_TO_TOP)
|
|
return E_INVALIDARG;
|
|
if (changed) *changed = format->readingdir != direction;
|
|
format->readingdir = direction;
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT format_set_wordwrapping(struct dwrite_textformat_data *format, DWRITE_WORD_WRAPPING wrapping, BOOL *changed)
|
|
{
|
|
if ((UINT32)wrapping > DWRITE_WORD_WRAPPING_CHARACTER)
|
|
return E_INVALIDARG;
|
|
if (changed) *changed = format->wrapping != wrapping;
|
|
format->wrapping = wrapping;
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT format_set_flowdirection(struct dwrite_textformat_data *format, DWRITE_FLOW_DIRECTION direction, BOOL *changed)
|
|
{
|
|
if ((UINT32)direction > DWRITE_FLOW_DIRECTION_RIGHT_TO_LEFT)
|
|
return E_INVALIDARG;
|
|
if (changed) *changed = format->flow != direction;
|
|
format->flow = direction;
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT format_set_trimming(struct dwrite_textformat_data *format, DWRITE_TRIMMING const *trimming,
|
|
IDWriteInlineObject *trimming_sign, BOOL *changed)
|
|
{
|
|
if (changed)
|
|
*changed = FALSE;
|
|
|
|
if ((UINT32)trimming->granularity > DWRITE_TRIMMING_GRANULARITY_WORD)
|
|
return E_INVALIDARG;
|
|
|
|
if (changed) {
|
|
*changed = !!memcmp(&format->trimming, trimming, sizeof(*trimming));
|
|
if (format->trimmingsign != trimming_sign)
|
|
*changed = TRUE;
|
|
}
|
|
|
|
format->trimming = *trimming;
|
|
if (format->trimmingsign)
|
|
IDWriteInlineObject_Release(format->trimmingsign);
|
|
format->trimmingsign = trimming_sign;
|
|
if (format->trimmingsign)
|
|
IDWriteInlineObject_AddRef(format->trimmingsign);
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT format_set_linespacing(struct dwrite_textformat_data *format, DWRITE_LINE_SPACING const *spacing, BOOL *changed)
|
|
{
|
|
if (spacing->height < 0.0f || spacing->leadingBefore < 0.0f || spacing->leadingBefore > 1.0f ||
|
|
(UINT32)spacing->method > DWRITE_LINE_SPACING_METHOD_PROPORTIONAL)
|
|
return E_INVALIDARG;
|
|
|
|
if (changed)
|
|
*changed = memcmp(spacing, &format->spacing, sizeof(*spacing));
|
|
|
|
format->spacing = *spacing;
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT format_set_font_axisvalues(struct dwrite_textformat_data *format, DWRITE_FONT_AXIS_VALUE const *axis_values,
|
|
unsigned int num_values)
|
|
{
|
|
free(format->axis_values);
|
|
format->axis_values = NULL;
|
|
format->axis_values_count = 0;
|
|
|
|
if (num_values)
|
|
{
|
|
if (!(format->axis_values = calloc(num_values, sizeof(*axis_values))))
|
|
return E_OUTOFMEMORY;
|
|
memcpy(format->axis_values, axis_values, num_values * sizeof(*axis_values));
|
|
format->axis_values_count = num_values;
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT format_get_font_axisvalues(struct dwrite_textformat_data *format, DWRITE_FONT_AXIS_VALUE *axis_values,
|
|
unsigned int num_values)
|
|
{
|
|
if (!format->axis_values_count)
|
|
{
|
|
if (num_values) memset(axis_values, 0, num_values * sizeof(*axis_values));
|
|
return S_OK;
|
|
}
|
|
|
|
if (num_values < format->axis_values_count)
|
|
return E_NOT_SUFFICIENT_BUFFER;
|
|
|
|
memcpy(axis_values, format->axis_values, min(num_values, format->axis_values_count) * sizeof(*axis_values));
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT format_get_fontfallback(const struct dwrite_textformat_data *format, IDWriteFontFallback **fallback)
|
|
{
|
|
*fallback = format->fallback;
|
|
if (*fallback)
|
|
IDWriteFontFallback_AddRef(*fallback);
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT format_set_fontfallback(struct dwrite_textformat_data *format, IDWriteFontFallback *fallback)
|
|
{
|
|
if (format->fallback)
|
|
IDWriteFontFallback_Release(format->fallback);
|
|
format->fallback = fallback;
|
|
if (fallback)
|
|
IDWriteFontFallback_AddRef(fallback);
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT format_set_optical_alignment(struct dwrite_textformat_data *format, DWRITE_OPTICAL_ALIGNMENT alignment)
|
|
{
|
|
if ((UINT32)alignment > DWRITE_OPTICAL_ALIGNMENT_NO_SIDE_BEARINGS)
|
|
return E_INVALIDARG;
|
|
format->optical_alignment = alignment;
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT format_set_vertical_orientation(struct dwrite_textformat_data *format, DWRITE_VERTICAL_GLYPH_ORIENTATION orientation,
|
|
BOOL *changed)
|
|
{
|
|
if ((UINT32)orientation > DWRITE_VERTICAL_GLYPH_ORIENTATION_STACKED)
|
|
return E_INVALIDARG;
|
|
|
|
if (changed)
|
|
*changed = format->vertical_orientation != orientation;
|
|
|
|
format->vertical_orientation = orientation;
|
|
return S_OK;
|
|
}
|
|
|
|
static HRESULT WINAPI dwritetextformat_QueryInterface(IDWriteTextFormat3 *iface, REFIID riid, void **obj)
|
|
{
|
|
TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
|
|
|
|
if (IsEqualIID(riid, &IID_IDWriteTextFormat3) ||
|
|
IsEqualIID(riid, &IID_IDWriteTextFormat2) ||
|
|
IsEqualIID(riid, &IID_IDWriteTextFormat1) ||
|
|
IsEqualIID(riid, &IID_IDWriteTextFormat) ||
|
|
IsEqualIID(riid, &IID_IUnknown))
|
|
{
|
|
*obj = iface;
|
|
IDWriteTextFormat3_AddRef(iface);
|
|
return S_OK;
|
|
}
|
|
|
|
WARN("%s not implemented.\n", debugstr_guid(riid));
|
|
|
|
*obj = NULL;
|
|
|
|
return E_NOINTERFACE;
|
|
}
|
|
|
|
static ULONG WINAPI dwritetextformat_AddRef(IDWriteTextFormat3 *iface)
|
|
{
|
|
struct dwrite_textformat *format = impl_from_IDWriteTextFormat3(iface);
|
|
ULONG refcount = InterlockedIncrement(&format->refcount);
|
|
|
|
TRACE("%p, refcount %ld.\n", iface, refcount);
|
|
|
|
return refcount;
|
|
}
|
|
|
|
static ULONG WINAPI dwritetextformat_Release(IDWriteTextFormat3 *iface)
|
|
{
|
|
struct dwrite_textformat *format = impl_from_IDWriteTextFormat3(iface);
|
|
ULONG refcount = InterlockedDecrement(&format->refcount);
|
|
|
|
TRACE("%p, refcount %ld.\n", iface, refcount);
|
|
|
|
if (!refcount)
|
|
{
|
|
release_format_data(&format->format);
|
|
free(format);
|
|
}
|
|
|
|
return refcount;
|
|
}
|
|
|
|
static HRESULT WINAPI dwritetextformat_SetTextAlignment(IDWriteTextFormat3 *iface, DWRITE_TEXT_ALIGNMENT alignment)
|
|
{
|
|
struct dwrite_textformat *format = impl_from_IDWriteTextFormat3(iface);
|
|
|
|
TRACE("%p, %d.\n", iface, alignment);
|
|
|
|
return format_set_textalignment(&format->format, alignment, NULL);
|
|
}
|
|
|
|
static HRESULT WINAPI dwritetextformat_SetParagraphAlignment(IDWriteTextFormat3 *iface,
|
|
DWRITE_PARAGRAPH_ALIGNMENT alignment)
|
|
{
|
|
struct dwrite_textformat *format = impl_from_IDWriteTextFormat3(iface);
|
|
|
|
TRACE("%p, %d.\n", iface, alignment);
|
|
|
|
return format_set_paralignment(&format->format, alignment, NULL);
|
|
}
|
|
|
|
static HRESULT WINAPI dwritetextformat_SetWordWrapping(IDWriteTextFormat3 *iface, DWRITE_WORD_WRAPPING wrapping)
|
|
{
|
|
struct dwrite_textformat *format = impl_from_IDWriteTextFormat3(iface);
|
|
|
|
TRACE("%p, %d.\n", iface, wrapping);
|
|
|
|
return format_set_wordwrapping(&format->format, wrapping, NULL);
|
|
}
|
|
|
|
static HRESULT WINAPI dwritetextformat_SetReadingDirection(IDWriteTextFormat3 *iface, DWRITE_READING_DIRECTION direction)
|
|
{
|
|
struct dwrite_textformat *format = impl_from_IDWriteTextFormat3(iface);
|
|
|
|
TRACE("%p, %d.\n", iface, direction);
|
|
|
|
return format_set_readingdirection(&format->format, direction, NULL);
|
|
}
|
|
|
|
static HRESULT WINAPI dwritetextformat_SetFlowDirection(IDWriteTextFormat3 *iface, DWRITE_FLOW_DIRECTION direction)
|
|
{
|
|
struct dwrite_textformat *format = impl_from_IDWriteTextFormat3(iface);
|
|
|
|
TRACE("%p, %d.\n", iface, direction);
|
|
|
|
return format_set_flowdirection(&format->format, direction, NULL);
|
|
}
|
|
|
|
static HRESULT WINAPI dwritetextformat_SetIncrementalTabStop(IDWriteTextFormat3 *iface, float tabstop)
|
|
{
|
|
struct dwrite_textformat *format = impl_from_IDWriteTextFormat3(iface);
|
|
|
|
TRACE("%p, %f.\n", iface, tabstop);
|
|
|
|
if (tabstop <= 0.0f)
|
|
return E_INVALIDARG;
|
|
|
|
format->format.tabstop = tabstop;
|
|
return S_OK;
|
|
}
|
|
|
|
static HRESULT WINAPI dwritetextformat_SetTrimming(IDWriteTextFormat3 *iface, DWRITE_TRIMMING const *trimming,
|
|
IDWriteInlineObject *trimming_sign)
|
|
{
|
|
struct dwrite_textformat *format = impl_from_IDWriteTextFormat3(iface);
|
|
|
|
TRACE("%p, %p, %p.\n", iface, trimming, trimming_sign);
|
|
|
|
return format_set_trimming(&format->format, trimming, trimming_sign, NULL);
|
|
}
|
|
|
|
static HRESULT WINAPI dwritetextformat_SetLineSpacing(IDWriteTextFormat3 *iface, DWRITE_LINE_SPACING_METHOD method,
|
|
float height, float baseline)
|
|
{
|
|
struct dwrite_textformat *format = impl_from_IDWriteTextFormat3(iface);
|
|
DWRITE_LINE_SPACING spacing;
|
|
|
|
TRACE("%p, %d, %f, %f.\n", iface, method, height, baseline);
|
|
|
|
spacing = format->format.spacing;
|
|
spacing.method = method;
|
|
spacing.height = height;
|
|
spacing.baseline = baseline;
|
|
|
|
return format_set_linespacing(&format->format, &spacing, NULL);
|
|
}
|
|
|
|
static DWRITE_TEXT_ALIGNMENT WINAPI dwritetextformat_GetTextAlignment(IDWriteTextFormat3 *iface)
|
|
{
|
|
struct dwrite_textformat *format = impl_from_IDWriteTextFormat3(iface);
|
|
|
|
TRACE("%p.\n", iface);
|
|
|
|
return format->format.textalignment;
|
|
}
|
|
|
|
static DWRITE_PARAGRAPH_ALIGNMENT WINAPI dwritetextformat_GetParagraphAlignment(IDWriteTextFormat3 *iface)
|
|
{
|
|
struct dwrite_textformat *format = impl_from_IDWriteTextFormat3(iface);
|
|
|
|
TRACE("%p.\n", iface);
|
|
|
|
return format->format.paralign;
|
|
}
|
|
|
|
static DWRITE_WORD_WRAPPING WINAPI dwritetextformat_GetWordWrapping(IDWriteTextFormat3 *iface)
|
|
{
|
|
struct dwrite_textformat *format = impl_from_IDWriteTextFormat3(iface);
|
|
|
|
TRACE("%p.\n", iface);
|
|
|
|
return format->format.wrapping;
|
|
}
|
|
|
|
static DWRITE_READING_DIRECTION WINAPI dwritetextformat_GetReadingDirection(IDWriteTextFormat3 *iface)
|
|
{
|
|
struct dwrite_textformat *format = impl_from_IDWriteTextFormat3(iface);
|
|
|
|
TRACE("%p.\n", iface);
|
|
|
|
return format->format.readingdir;
|
|
}
|
|
|
|
static DWRITE_FLOW_DIRECTION WINAPI dwritetextformat_GetFlowDirection(IDWriteTextFormat3 *iface)
|
|
{
|
|
struct dwrite_textformat *format = impl_from_IDWriteTextFormat3(iface);
|
|
|
|
TRACE("%p.\n", iface);
|
|
|
|
return format->format.flow;
|
|
}
|
|
|
|
static float WINAPI dwritetextformat_GetIncrementalTabStop(IDWriteTextFormat3 *iface)
|
|
{
|
|
struct dwrite_textformat *format = impl_from_IDWriteTextFormat3(iface);
|
|
|
|
TRACE("%p.\n", iface);
|
|
|
|
return format->format.tabstop;
|
|
}
|
|
|
|
static HRESULT WINAPI dwritetextformat_GetTrimming(IDWriteTextFormat3 *iface, DWRITE_TRIMMING *options,
|
|
IDWriteInlineObject **trimming_sign)
|
|
{
|
|
struct dwrite_textformat *format = impl_from_IDWriteTextFormat3(iface);
|
|
|
|
TRACE("%p, %p, %p.\n", iface, options, trimming_sign);
|
|
|
|
*options = format->format.trimming;
|
|
if ((*trimming_sign = format->format.trimmingsign))
|
|
IDWriteInlineObject_AddRef(*trimming_sign);
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
static HRESULT WINAPI dwritetextformat_GetLineSpacing(IDWriteTextFormat3 *iface, DWRITE_LINE_SPACING_METHOD *method,
|
|
float *spacing, float *baseline)
|
|
{
|
|
struct dwrite_textformat *format = impl_from_IDWriteTextFormat3(iface);
|
|
|
|
TRACE("%p, %p, %p, %p.\n", iface, method, spacing, baseline);
|
|
|
|
*method = format->format.spacing.method;
|
|
*spacing = format->format.spacing.height;
|
|
*baseline = format->format.spacing.baseline;
|
|
return S_OK;
|
|
}
|
|
|
|
static HRESULT WINAPI dwritetextformat_GetFontCollection(IDWriteTextFormat3 *iface, IDWriteFontCollection **collection)
|
|
{
|
|
struct dwrite_textformat *format = impl_from_IDWriteTextFormat3(iface);
|
|
|
|
TRACE("%p, %p.\n", iface, collection);
|
|
|
|
*collection = format->format.collection;
|
|
IDWriteFontCollection_AddRef(*collection);
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
static UINT32 WINAPI dwritetextformat_GetFontFamilyNameLength(IDWriteTextFormat3 *iface)
|
|
{
|
|
struct dwrite_textformat *format = impl_from_IDWriteTextFormat3(iface);
|
|
|
|
TRACE("%p.\n", iface);
|
|
|
|
return format->format.family_len;
|
|
}
|
|
|
|
static HRESULT WINAPI dwritetextformat_GetFontFamilyName(IDWriteTextFormat3 *iface, WCHAR *name, UINT32 size)
|
|
{
|
|
struct dwrite_textformat *format = impl_from_IDWriteTextFormat3(iface);
|
|
|
|
TRACE("%p, %p, %u.\n", iface, name, size);
|
|
|
|
if (size <= format->format.family_len)
|
|
return E_NOT_SUFFICIENT_BUFFER;
|
|
wcscpy(name, format->format.family_name);
|
|
return S_OK;
|
|
}
|
|
|
|
static DWRITE_FONT_WEIGHT WINAPI dwritetextformat_GetFontWeight(IDWriteTextFormat3 *iface)
|
|
{
|
|
struct dwrite_textformat *format = impl_from_IDWriteTextFormat3(iface);
|
|
|
|
TRACE("%p.\n", iface);
|
|
|
|
return format->format.weight;
|
|
}
|
|
|
|
static DWRITE_FONT_STYLE WINAPI dwritetextformat_GetFontStyle(IDWriteTextFormat3 *iface)
|
|
{
|
|
struct dwrite_textformat *format = impl_from_IDWriteTextFormat3(iface);
|
|
|
|
TRACE("%p.\n", iface);
|
|
|
|
return format->format.style;
|
|
}
|
|
|
|
static DWRITE_FONT_STRETCH WINAPI dwritetextformat_GetFontStretch(IDWriteTextFormat3 *iface)
|
|
{
|
|
struct dwrite_textformat *format = impl_from_IDWriteTextFormat3(iface);
|
|
|
|
TRACE("%p.\n", iface);
|
|
|
|
return format->format.stretch;
|
|
}
|
|
|
|
static float WINAPI dwritetextformat_GetFontSize(IDWriteTextFormat3 *iface)
|
|
{
|
|
struct dwrite_textformat *format = impl_from_IDWriteTextFormat3(iface);
|
|
|
|
TRACE("%p.\n", iface);
|
|
|
|
return format->format.fontsize;
|
|
}
|
|
|
|
static UINT32 WINAPI dwritetextformat_GetLocaleNameLength(IDWriteTextFormat3 *iface)
|
|
{
|
|
struct dwrite_textformat *format = impl_from_IDWriteTextFormat3(iface);
|
|
|
|
TRACE("%p.\n", iface);
|
|
|
|
return format->format.locale_len;
|
|
}
|
|
|
|
static HRESULT WINAPI dwritetextformat_GetLocaleName(IDWriteTextFormat3 *iface, WCHAR *name, UINT32 size)
|
|
{
|
|
struct dwrite_textformat *format = impl_from_IDWriteTextFormat3(iface);
|
|
|
|
TRACE("%p, %p %u.\n", iface, name, size);
|
|
|
|
if (size <= format->format.locale_len)
|
|
return E_NOT_SUFFICIENT_BUFFER;
|
|
wcscpy(name, format->format.locale);
|
|
return S_OK;
|
|
}
|
|
|
|
static HRESULT WINAPI dwritetextformat1_SetVerticalGlyphOrientation(IDWriteTextFormat3 *iface,
|
|
DWRITE_VERTICAL_GLYPH_ORIENTATION orientation)
|
|
{
|
|
struct dwrite_textformat *format = impl_from_IDWriteTextFormat3(iface);
|
|
|
|
TRACE("%p, %d.\n", iface, orientation);
|
|
|
|
return format_set_vertical_orientation(&format->format, orientation, NULL);
|
|
}
|
|
|
|
static DWRITE_VERTICAL_GLYPH_ORIENTATION WINAPI dwritetextformat1_GetVerticalGlyphOrientation(IDWriteTextFormat3 *iface)
|
|
{
|
|
struct dwrite_textformat *format = impl_from_IDWriteTextFormat3(iface);
|
|
|
|
TRACE("%p.\n", iface);
|
|
|
|
return format->format.vertical_orientation;
|
|
}
|
|
|
|
static HRESULT WINAPI dwritetextformat1_SetLastLineWrapping(IDWriteTextFormat3 *iface, BOOL lastline_wrapping_enabled)
|
|
{
|
|
struct dwrite_textformat *format = impl_from_IDWriteTextFormat3(iface);
|
|
|
|
TRACE("%p, %d.\n", iface, lastline_wrapping_enabled);
|
|
|
|
format->format.last_line_wrapping = !!lastline_wrapping_enabled;
|
|
return S_OK;
|
|
}
|
|
|
|
static BOOL WINAPI dwritetextformat1_GetLastLineWrapping(IDWriteTextFormat3 *iface)
|
|
{
|
|
struct dwrite_textformat *format = impl_from_IDWriteTextFormat3(iface);
|
|
|
|
TRACE("%p.\n", iface);
|
|
|
|
return format->format.last_line_wrapping;
|
|
}
|
|
|
|
static HRESULT WINAPI dwritetextformat1_SetOpticalAlignment(IDWriteTextFormat3 *iface, DWRITE_OPTICAL_ALIGNMENT alignment)
|
|
{
|
|
struct dwrite_textformat *format = impl_from_IDWriteTextFormat3(iface);
|
|
|
|
TRACE("%p, %d.\n", iface, alignment);
|
|
|
|
return format_set_optical_alignment(&format->format, alignment);
|
|
}
|
|
|
|
static DWRITE_OPTICAL_ALIGNMENT WINAPI dwritetextformat1_GetOpticalAlignment(IDWriteTextFormat3 *iface)
|
|
{
|
|
struct dwrite_textformat *format = impl_from_IDWriteTextFormat3(iface);
|
|
|
|
TRACE("%p.\n", iface);
|
|
|
|
return format->format.optical_alignment;
|
|
}
|
|
|
|
static HRESULT WINAPI dwritetextformat1_SetFontFallback(IDWriteTextFormat3 *iface, IDWriteFontFallback *fallback)
|
|
{
|
|
struct dwrite_textformat *format = impl_from_IDWriteTextFormat3(iface);
|
|
|
|
TRACE("%p, %p.\n", iface, fallback);
|
|
|
|
return format_set_fontfallback(&format->format, fallback);
|
|
}
|
|
|
|
static HRESULT WINAPI dwritetextformat1_GetFontFallback(IDWriteTextFormat3 *iface, IDWriteFontFallback **fallback)
|
|
{
|
|
struct dwrite_textformat *format = impl_from_IDWriteTextFormat3(iface);
|
|
|
|
TRACE("%p, %p.\n", iface, fallback);
|
|
|
|
return format_get_fontfallback(&format->format, fallback);
|
|
}
|
|
|
|
static HRESULT WINAPI dwritetextformat2_SetLineSpacing(IDWriteTextFormat3 *iface, DWRITE_LINE_SPACING const *spacing)
|
|
{
|
|
struct dwrite_textformat *format = impl_from_IDWriteTextFormat3(iface);
|
|
|
|
TRACE("%p, %p.\n", iface, spacing);
|
|
|
|
return format_set_linespacing(&format->format, spacing, NULL);
|
|
}
|
|
|
|
static HRESULT WINAPI dwritetextformat2_GetLineSpacing(IDWriteTextFormat3 *iface, DWRITE_LINE_SPACING *spacing)
|
|
{
|
|
struct dwrite_textformat *format = impl_from_IDWriteTextFormat3(iface);
|
|
|
|
TRACE("%p, %p.\n", iface, spacing);
|
|
|
|
*spacing = format->format.spacing;
|
|
return S_OK;
|
|
}
|
|
|
|
static HRESULT WINAPI dwritetextformat3_SetFontAxisValues(IDWriteTextFormat3 *iface,
|
|
DWRITE_FONT_AXIS_VALUE const *axis_values, UINT32 num_values)
|
|
{
|
|
struct dwrite_textformat *format = impl_from_IDWriteTextFormat3(iface);
|
|
|
|
TRACE("%p, %p, %u.\n", iface, axis_values, num_values);
|
|
|
|
return format_set_font_axisvalues(&format->format, axis_values, num_values);
|
|
}
|
|
|
|
static UINT32 WINAPI dwritetextformat3_GetFontAxisValueCount(IDWriteTextFormat3 *iface)
|
|
{
|
|
struct dwrite_textformat *format = impl_from_IDWriteTextFormat3(iface);
|
|
|
|
TRACE("%p.\n", iface);
|
|
|
|
return format->format.axis_values_count;
|
|
}
|
|
|
|
static HRESULT WINAPI dwritetextformat3_GetFontAxisValues(IDWriteTextFormat3 *iface,
|
|
DWRITE_FONT_AXIS_VALUE *axis_values, UINT32 num_values)
|
|
{
|
|
struct dwrite_textformat *format = impl_from_IDWriteTextFormat3(iface);
|
|
|
|
TRACE("%p, %p, %u.\n", iface, axis_values, num_values);
|
|
|
|
return format_get_font_axisvalues(&format->format, axis_values, num_values);
|
|
}
|
|
|
|
static DWRITE_AUTOMATIC_FONT_AXES WINAPI dwritetextformat3_GetAutomaticFontAxes(IDWriteTextFormat3 *iface)
|
|
{
|
|
struct dwrite_textformat *format = impl_from_IDWriteTextFormat3(iface);
|
|
|
|
TRACE("%p.\n", iface);
|
|
|
|
return format->format.automatic_axes;
|
|
}
|
|
|
|
static HRESULT WINAPI dwritetextformat3_SetAutomaticFontAxes(IDWriteTextFormat3 *iface, DWRITE_AUTOMATIC_FONT_AXES axes)
|
|
{
|
|
struct dwrite_textformat *format = impl_from_IDWriteTextFormat3(iface);
|
|
|
|
TRACE("%p, %d.\n", iface, axes);
|
|
|
|
format->format.automatic_axes = axes;
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
static const IDWriteTextFormat3Vtbl dwritetextformatvtbl =
|
|
{
|
|
dwritetextformat_QueryInterface,
|
|
dwritetextformat_AddRef,
|
|
dwritetextformat_Release,
|
|
dwritetextformat_SetTextAlignment,
|
|
dwritetextformat_SetParagraphAlignment,
|
|
dwritetextformat_SetWordWrapping,
|
|
dwritetextformat_SetReadingDirection,
|
|
dwritetextformat_SetFlowDirection,
|
|
dwritetextformat_SetIncrementalTabStop,
|
|
dwritetextformat_SetTrimming,
|
|
dwritetextformat_SetLineSpacing,
|
|
dwritetextformat_GetTextAlignment,
|
|
dwritetextformat_GetParagraphAlignment,
|
|
dwritetextformat_GetWordWrapping,
|
|
dwritetextformat_GetReadingDirection,
|
|
dwritetextformat_GetFlowDirection,
|
|
dwritetextformat_GetIncrementalTabStop,
|
|
dwritetextformat_GetTrimming,
|
|
dwritetextformat_GetLineSpacing,
|
|
dwritetextformat_GetFontCollection,
|
|
dwritetextformat_GetFontFamilyNameLength,
|
|
dwritetextformat_GetFontFamilyName,
|
|
dwritetextformat_GetFontWeight,
|
|
dwritetextformat_GetFontStyle,
|
|
dwritetextformat_GetFontStretch,
|
|
dwritetextformat_GetFontSize,
|
|
dwritetextformat_GetLocaleNameLength,
|
|
dwritetextformat_GetLocaleName,
|
|
dwritetextformat1_SetVerticalGlyphOrientation,
|
|
dwritetextformat1_GetVerticalGlyphOrientation,
|
|
dwritetextformat1_SetLastLineWrapping,
|
|
dwritetextformat1_GetLastLineWrapping,
|
|
dwritetextformat1_SetOpticalAlignment,
|
|
dwritetextformat1_GetOpticalAlignment,
|
|
dwritetextformat1_SetFontFallback,
|
|
dwritetextformat1_GetFontFallback,
|
|
dwritetextformat2_SetLineSpacing,
|
|
dwritetextformat2_GetLineSpacing,
|
|
dwritetextformat3_SetFontAxisValues,
|
|
dwritetextformat3_GetFontAxisValueCount,
|
|
dwritetextformat3_GetFontAxisValues,
|
|
dwritetextformat3_GetAutomaticFontAxes,
|
|
dwritetextformat3_SetAutomaticFontAxes,
|
|
};
|
|
|
|
struct dwrite_textformat *unsafe_impl_from_IDWriteTextFormat(IDWriteTextFormat *iface)
|
|
{
|
|
return (iface->lpVtbl == (IDWriteTextFormatVtbl *)&dwritetextformatvtbl) ?
|
|
CONTAINING_RECORD(iface, struct dwrite_textformat, IDWriteTextFormat3_iface) : NULL;
|
|
}
|
|
|
|
HRESULT create_textformat(const WCHAR *family_name, IDWriteFontCollection *collection, DWRITE_FONT_WEIGHT weight,
|
|
DWRITE_FONT_STYLE style, DWRITE_FONT_STRETCH stretch, float size, const WCHAR *locale, IDWriteTextFormat **format)
|
|
{
|
|
struct dwrite_textformat *object;
|
|
|
|
*format = NULL;
|
|
|
|
if (size <= 0.0f)
|
|
return E_INVALIDARG;
|
|
|
|
if (((UINT32)weight > DWRITE_FONT_WEIGHT_ULTRA_BLACK) ||
|
|
((UINT32)stretch > DWRITE_FONT_STRETCH_ULTRA_EXPANDED) ||
|
|
((UINT32)style > DWRITE_FONT_STYLE_ITALIC))
|
|
return E_INVALIDARG;
|
|
|
|
if (!(object = calloc(1, sizeof(*object))))
|
|
return E_OUTOFMEMORY;
|
|
|
|
object->IDWriteTextFormat3_iface.lpVtbl = &dwritetextformatvtbl;
|
|
object->refcount = 1;
|
|
object->format.family_name = wcsdup(family_name);
|
|
object->format.family_len = wcslen(family_name);
|
|
object->format.locale = wcsdup(locale);
|
|
object->format.locale_len = wcslen(locale);
|
|
/* Force locale name to lower case, layout will inherit this modified value. */
|
|
wcslwr(object->format.locale);
|
|
object->format.weight = weight;
|
|
object->format.style = style;
|
|
object->format.fontsize = size;
|
|
object->format.tabstop = 4.0f * size;
|
|
object->format.stretch = stretch;
|
|
object->format.last_line_wrapping = TRUE;
|
|
object->format.collection = collection;
|
|
IDWriteFontCollection_AddRef(object->format.collection);
|
|
|
|
*format = (IDWriteTextFormat *)&object->IDWriteTextFormat3_iface;
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
static HRESULT WINAPI dwritetrimmingsign_QueryInterface(IDWriteInlineObject *iface, REFIID riid, void **obj)
|
|
{
|
|
TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
|
|
|
|
if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IDWriteInlineObject)) {
|
|
*obj = iface;
|
|
IDWriteInlineObject_AddRef(iface);
|
|
return S_OK;
|
|
}
|
|
|
|
WARN("%s not implemented.\n", debugstr_guid(riid));
|
|
|
|
*obj = NULL;
|
|
return E_NOINTERFACE;
|
|
}
|
|
|
|
static ULONG WINAPI dwritetrimmingsign_AddRef(IDWriteInlineObject *iface)
|
|
{
|
|
struct dwrite_trimmingsign *sign = impl_from_IDWriteInlineObject(iface);
|
|
ULONG refcount = InterlockedIncrement(&sign->refcount);
|
|
|
|
TRACE("%p, refcount %ld.\n", iface, refcount);
|
|
|
|
return refcount;
|
|
}
|
|
|
|
static ULONG WINAPI dwritetrimmingsign_Release(IDWriteInlineObject *iface)
|
|
{
|
|
struct dwrite_trimmingsign *sign = impl_from_IDWriteInlineObject(iface);
|
|
ULONG refcount = InterlockedDecrement(&sign->refcount);
|
|
|
|
TRACE("%p, refcount %ld.\n", iface, refcount);
|
|
|
|
if (!refcount)
|
|
{
|
|
IDWriteTextLayout_Release(sign->layout);
|
|
free(sign);
|
|
}
|
|
|
|
return refcount;
|
|
}
|
|
|
|
static HRESULT WINAPI dwritetrimmingsign_Draw(IDWriteInlineObject *iface, void *context, IDWriteTextRenderer *renderer,
|
|
float originX, float originY, BOOL is_sideways, BOOL is_rtl, IUnknown *effect)
|
|
{
|
|
struct dwrite_trimmingsign *sign = impl_from_IDWriteInlineObject(iface);
|
|
DWRITE_LINE_METRICS line;
|
|
UINT32 line_count;
|
|
|
|
TRACE("%p, %p, %p, %.2f, %.2f, %d, %d, %p.\n", iface, context, renderer, originX, originY,
|
|
is_sideways, is_rtl, effect);
|
|
|
|
IDWriteTextLayout_GetLineMetrics(sign->layout, &line, 1, &line_count);
|
|
return IDWriteTextLayout_Draw(sign->layout, context, renderer, originX, originY - line.baseline);
|
|
}
|
|
|
|
static HRESULT WINAPI dwritetrimmingsign_GetMetrics(IDWriteInlineObject *iface, DWRITE_INLINE_OBJECT_METRICS *ret)
|
|
{
|
|
struct dwrite_trimmingsign *sign = impl_from_IDWriteInlineObject(iface);
|
|
DWRITE_TEXT_METRICS metrics;
|
|
HRESULT hr;
|
|
|
|
TRACE("%p, %p.\n", iface, ret);
|
|
|
|
hr = IDWriteTextLayout_GetMetrics(sign->layout, &metrics);
|
|
if (FAILED(hr))
|
|
{
|
|
memset(ret, 0, sizeof(*ret));
|
|
return hr;
|
|
}
|
|
|
|
ret->width = metrics.width;
|
|
ret->height = 0.0f;
|
|
ret->baseline = 0.0f;
|
|
ret->supportsSideways = FALSE;
|
|
return S_OK;
|
|
}
|
|
|
|
static HRESULT WINAPI dwritetrimmingsign_GetOverhangMetrics(IDWriteInlineObject *iface, DWRITE_OVERHANG_METRICS *overhangs)
|
|
{
|
|
struct dwrite_trimmingsign *sign = impl_from_IDWriteInlineObject(iface);
|
|
|
|
TRACE("%p, %p.\n", iface, overhangs);
|
|
|
|
return IDWriteTextLayout_GetOverhangMetrics(sign->layout, overhangs);
|
|
}
|
|
|
|
static HRESULT WINAPI dwritetrimmingsign_GetBreakConditions(IDWriteInlineObject *iface, DWRITE_BREAK_CONDITION *before,
|
|
DWRITE_BREAK_CONDITION *after)
|
|
{
|
|
TRACE("%p, %p, %p.\n", iface, before, after);
|
|
|
|
*before = *after = DWRITE_BREAK_CONDITION_NEUTRAL;
|
|
return S_OK;
|
|
}
|
|
|
|
static const IDWriteInlineObjectVtbl dwritetrimmingsignvtbl =
|
|
{
|
|
dwritetrimmingsign_QueryInterface,
|
|
dwritetrimmingsign_AddRef,
|
|
dwritetrimmingsign_Release,
|
|
dwritetrimmingsign_Draw,
|
|
dwritetrimmingsign_GetMetrics,
|
|
dwritetrimmingsign_GetOverhangMetrics,
|
|
dwritetrimmingsign_GetBreakConditions
|
|
};
|
|
|
|
static inline BOOL is_reading_direction_horz(DWRITE_READING_DIRECTION direction)
|
|
{
|
|
return (direction == DWRITE_READING_DIRECTION_LEFT_TO_RIGHT) ||
|
|
(direction == DWRITE_READING_DIRECTION_RIGHT_TO_LEFT);
|
|
}
|
|
|
|
static inline BOOL is_reading_direction_vert(DWRITE_READING_DIRECTION direction)
|
|
{
|
|
return (direction == DWRITE_READING_DIRECTION_TOP_TO_BOTTOM) ||
|
|
(direction == DWRITE_READING_DIRECTION_BOTTOM_TO_TOP);
|
|
}
|
|
|
|
static inline BOOL is_flow_direction_horz(DWRITE_FLOW_DIRECTION direction)
|
|
{
|
|
return (direction == DWRITE_FLOW_DIRECTION_LEFT_TO_RIGHT) ||
|
|
(direction == DWRITE_FLOW_DIRECTION_RIGHT_TO_LEFT);
|
|
}
|
|
|
|
static inline BOOL is_flow_direction_vert(DWRITE_FLOW_DIRECTION direction)
|
|
{
|
|
return (direction == DWRITE_FLOW_DIRECTION_TOP_TO_BOTTOM) ||
|
|
(direction == DWRITE_FLOW_DIRECTION_BOTTOM_TO_TOP);
|
|
}
|
|
|
|
HRESULT create_trimmingsign(IDWriteFactory7 *factory, IDWriteTextFormat *format, IDWriteInlineObject **sign)
|
|
{
|
|
struct dwrite_trimmingsign *object;
|
|
DWRITE_READING_DIRECTION reading;
|
|
DWRITE_FLOW_DIRECTION flow;
|
|
HRESULT hr;
|
|
|
|
*sign = NULL;
|
|
|
|
if (!format)
|
|
return E_INVALIDARG;
|
|
|
|
/* Validate reading/flow direction here, layout creation won't complain about
|
|
invalid combinations. */
|
|
reading = IDWriteTextFormat_GetReadingDirection(format);
|
|
flow = IDWriteTextFormat_GetFlowDirection(format);
|
|
|
|
if ((is_reading_direction_horz(reading) && is_flow_direction_horz(flow)) ||
|
|
(is_reading_direction_vert(reading) && is_flow_direction_vert(flow)))
|
|
return DWRITE_E_FLOWDIRECTIONCONFLICTS;
|
|
|
|
if (!(object = calloc(1, sizeof(*object))))
|
|
return E_OUTOFMEMORY;
|
|
|
|
object->IDWriteInlineObject_iface.lpVtbl = &dwritetrimmingsignvtbl;
|
|
object->refcount = 1;
|
|
|
|
hr = IDWriteFactory7_CreateTextLayout(factory, L"\x2026", 1, format, 0.0f, 0.0f, &object->layout);
|
|
if (FAILED(hr))
|
|
{
|
|
free(object);
|
|
return hr;
|
|
}
|
|
|
|
IDWriteTextLayout_SetWordWrapping(object->layout, DWRITE_WORD_WRAPPING_NO_WRAP);
|
|
IDWriteTextLayout_SetParagraphAlignment(object->layout, DWRITE_PARAGRAPH_ALIGNMENT_NEAR);
|
|
IDWriteTextLayout_SetTextAlignment(object->layout, DWRITE_TEXT_ALIGNMENT_LEADING);
|
|
|
|
*sign = &object->IDWriteInlineObject_iface;
|
|
|
|
return S_OK;
|
|
}
|