RefPtr<IDWriteFontFamily> family = DWriteFactory::FindSystemFontFamily(face_name); delete[] face_name; if (!family) { /* If the family is not found, use the default that should always exist. */
face_name_len = MultiByteToWideChar(CP_UTF8, 0, CAIRO_FONT_FAMILY_DEFAULT, -1, NULL, 0);
face_name = new WCHAR[face_name_len];
MultiByteToWideChar(CP_UTF8, 0, CAIRO_FONT_FAMILY_DEFAULT, -1, face_name, face_name_len);
family = DWriteFactory::FindSystemFontFamily(face_name); delete[] face_name; if (!family) {
*font_face = (cairo_font_face_t*)&_cairo_font_face_nil; return (cairo_status_t)CAIRO_INT_STATUS_UNSUPPORTED;
}
}
DWRITE_FONT_WEIGHT weight; switch (toy_face->weight) { case CAIRO_FONT_WEIGHT_BOLD:
weight = DWRITE_FONT_WEIGHT_BOLD; break; case CAIRO_FONT_WEIGHT_NORMAL: default:
weight = DWRITE_FONT_WEIGHT_NORMAL; break;
}
DWRITE_FONT_STYLE style; switch (toy_face->slant) { case CAIRO_FONT_SLANT_ITALIC:
style = DWRITE_FONT_STYLE_ITALIC; break; case CAIRO_FONT_SLANT_OBLIQUE:
style = DWRITE_FONT_STYLE_OBLIQUE; break; case CAIRO_FONT_SLANT_NORMAL: default:
style = DWRITE_FONT_STYLE_NORMAL; break;
}
if (scaled_font->mat.xy == 0 && scaled_font->mat.yx == 0 &&
scaled_font->mat.xx == scaled_font->base.font_matrix.xx &&
scaled_font->mat.yy == scaled_font->base.font_matrix.yy) { // Fast route, don't actually use a transform but just // set the correct font size.
*transformed = 0;
for (int i = 0; i < num_glyphs; i++) {
indices[i] = (WORD) glyphs[i].index;
offsets[i].ascenderOffset = -(FLOAT)(glyphs[i].y);
offsets[i].advanceOffset = (FLOAT)(glyphs[i].x);
advances[i] = 0.0;
}
} else {
*transformed = 1; // Transforming positions by the inverse matrix, then by the original // matrix later may introduce small errors, especially because the // D2D matrix is single-precision whereas the cairo one is double. // This is a problem when glyph positions were originally at exactly // half-pixel locations, which eventually round to whole pixels for // GDI rendering - the errors introduced here cause them to round in // unpredictable directions, instead of all rounding in a consistent // way, leading to poor glyph spacing (bug 675383). // To mitigate this, nudge the positions by a tiny amount to try and // ensure that after the two transforms, they'll still round in a // consistent direction. constdouble EPSILON = 0.0001; for (int i = 0; i < num_glyphs; i++) {
indices[i] = (WORD) glyphs[i].index; double x = glyphs[i].x + EPSILON; double y = glyphs[i].y;
cairo_matrix_transform_point(&scaled_font->mat_inverse, &x, &y); // Since we will multiply by our ctm matrix later for rotation effects // and such, adjust positions by the inverse matrix now. Y-axis is // inverted! Therefor the offset is -y.
offsets[i].ascenderOffset = -(FLOAT)y;
offsets[i].advanceOffset = (FLOAT)x;
advances[i] = 0.0;
} // The font matrix takes care of the scaling if we have a transform, // emSize should be 1.
run->fontEmSize = 1.0f;
}
}
/* Must do malloc and not C++ new, since Cairo frees this. */
cairo_dwrite_scaled_font_t *dwrite_font = (cairo_dwrite_scaled_font_t*)_cairo_calloc( sizeof(cairo_dwrite_scaled_font_t)); if (unlikely(dwrite_font == NULL)) return _cairo_error (CAIRO_STATUS_NO_MEMORY);
*font = reinterpret_cast<cairo_scaled_font_t*>(dwrite_font);
status = _cairo_scaled_font_init (&dwrite_font->base,
&font_face->base,
font_matrix,
ctm,
options,
&_cairo_dwrite_scaled_font_backend); if (status) {
free(dwrite_font); return status;
}
if (options->variations) {
RefPtr<IDWriteFontFace5> dwriteface5;
/* Since Windows 10 20348 */ if (SUCCEEDED (font_face->dwriteface->QueryInterface(&dwriteface5))) {
RefPtr<IDWriteFontResource> dwritefontresource;
if (dwriteface5->HasVariations () &&
SUCCEEDED (dwriteface5->GetFontResource (&dwritefontresource)))
{
UINT32 count = MIN (dwriteface5->GetFontAxisValueCount (), 500);
DWRITE_FONT_AXIS_VALUE *dwrite_axes = new DWRITE_FONT_AXIS_VALUE[count];
UINT32 variables_count = 0;
/* Sort variable axes first */ for (UINT32 i = 0; i < count; i++) { if (dwritefontresource->GetFontAxisAttributes (i) & DWRITE_FONT_AXIS_ATTRIBUTES_VARIABLE) { if (variables_count != i) {
DWRITE_FONT_AXIS_VALUE swap_aux = dwrite_axes[variables_count];
dwrite_axes[variables_count] = dwrite_axes[i];
dwrite_axes[i] = swap_aux;
}
variables_count++;
}
}
if (SUCCEEDED (dwriteface5->GetFontAxisValues(dwrite_axes, count))) {
RefPtr<IDWriteFontFace5> dwriteface_new5;
// The following code detects the system quality at scaled_font creation time, // this means that if cleartype settings are changed but the scaled_fonts // are re-used, they might not adhere to the new system setting until re- // creation. switch (cairo_win32_get_system_text_quality()) { case CLEARTYPE_QUALITY:
default_quality = CAIRO_ANTIALIAS_SUBPIXEL; break; case ANTIALIASED_QUALITY:
default_quality = CAIRO_ANTIALIAS_GRAY; break; case DEFAULT_QUALITY: // _get_system_quality() seems to think aliased is default!
default_quality = CAIRO_ANTIALIAS_NONE; break;
}
if (default_quality == CAIRO_ANTIALIAS_GRAY) { if (!do_grayscale(dwrite_font->dwriteface, (unsignedint)_cairo_round(font_matrix->yy))) {
default_quality = CAIRO_ANTIALIAS_NONE;
}
}
if ((info & CAIRO_SCALED_GLYPH_INFO_METRICS) != 0) {
status = _cairo_dwrite_scaled_font_init_glyph_metrics (scaled_dwrite_font, scaled_glyph); if (status) return status;
}
if (info & CAIRO_SCALED_GLYPH_INFO_COLOR_SURFACE) {
status = _cairo_dwrite_scaled_font_init_glyph_color_surface (scaled_dwrite_font, scaled_glyph, foreground_color); if (status) return status;
}
if (info & CAIRO_SCALED_GLYPH_INFO_SURFACE) {
status = _cairo_dwrite_scaled_font_init_glyph_surface (scaled_dwrite_font, scaled_glyph); if (status) return status;
}
if ((info & CAIRO_SCALED_GLYPH_INFO_PATH) != 0) {
status = _cairo_dwrite_scaled_font_init_glyph_path (scaled_dwrite_font, scaled_glyph); if (status) return status;
}
// We pad the extents here because GetDesignGlyphMetrics returns "ideal" metrics // for the glyph outline, without accounting for hinting/gridfitting/antialiasing, // and therefore it does not always cover all pixels that will actually be touched. if (extents.width > 0 && extents.height > 0) { double x = 1, y = 1;
cairo_matrix_transform_distance (&scaled_font->mat_inverse, &x, &y);
x = fabs(x);
y = fabs(y);
extents.width += x * 2;
extents.x_bearing -= x;
extents.height += y * 2;
extents.y_bearing -= y;
}
/* The list of glyph image formats this renderer is prepared to support. */
DWRITE_GLYPH_IMAGE_FORMATS supported_formats = static_cast<DWRITE_GLYPH_IMAGE_FORMATS>(
DWRITE_GLYPH_IMAGE_FORMATS_COLR |
DWRITE_GLYPH_IMAGE_FORMATS_SVG |
DWRITE_GLYPH_IMAGE_FORMATS_PNG |
DWRITE_GLYPH_IMAGE_FORMATS_JPEG |
DWRITE_GLYPH_IMAGE_FORMATS_TIFF |
DWRITE_GLYPH_IMAGE_FORMATS_PREMULTIPLIED_B8G8R8A8);
if (hr == DWRITE_E_NOCOLOR) { /* No color glyphs */
scaled_glyph->color_glyph = FALSE;
scaled_glyph->color_glyph_set = TRUE; return CAIRO_INT_STATUS_UNSUPPORTED;
}
if (FAILED(hr)) return _cairo_dwrite_error (hr, "TranslateColorGlyphRun failed");
/* We have a color glyph(s). Use Direct2D to render it to a bitmap */ if (!WICImagingFactory::Instance() || !D2DFactory::Instance()) return _cairo_dwrite_error (hr, "Instance failed");
// Helper for OS versions up to Windows 8 static cairo_int_status_t
init_glyph_surface_fallback_a8 (cairo_dwrite_scaled_font_t *scaled_font,
cairo_scaled_glyph_t *scaled_glyph, int width, int height, double x1, double y1,
DWRITE_MATRIX *matrix,
DWRITE_GLYPH_RUN *run)
{
RefPtr<IWICBitmap> bitmap;
HRESULT hr;
if (width <= 0)
width = 1; if (height <= 0)
height = 1;
FLOAT advance = 0;
UINT16 index = (UINT16)_cairo_scaled_glyph_index (scaled_glyph);
DWRITE_GLYPH_OFFSET offset; double x = -x1 + .25 * _cairo_scaled_glyph_xphase (scaled_glyph); double y = -y1 + .25 * _cairo_scaled_glyph_yphase (scaled_glyph);
/* We transform by the inverse transformation here. This will put our glyph *locationsinthespaceinwhichwedraw.Whichislatertransformedby *thetransformationmatrixthatweuse.Thiswilltransformthe *glyphpositionsbacktowheretheywerebeforewhendrawing,butthe
* glyph shapes will be transformed by the transformation matrix. */
cairo_matrix_transform_point(&scaled_font->mat_inverse, &x, &y);
offset.advanceOffset = (FLOAT)x;
offset.ascenderOffset = -(FLOAT)y; /* Y axis is inverted */
// Reduce the many Cairo antialias values to the // three we actually care about: NONE, GRAY, RGB enum {
ANTIALIAS_NONE,
ANTIALIAS_GRAY,
ANTIALIAS_CLEARTYPE,
} antialias = ANTIALIAS_CLEARTYPE;
switch (scaled_font->antialias_mode) { case CAIRO_ANTIALIAS_NONE:
antialias = ANTIALIAS_NONE; break; case CAIRO_ANTIALIAS_FAST: case CAIRO_ANTIALIAS_GRAY:
antialias = ANTIALIAS_GRAY; break; case CAIRO_ANTIALIAS_DEFAULT: case CAIRO_ANTIALIAS_GOOD: case CAIRO_ANTIALIAS_BEST: case CAIRO_ANTIALIAS_SUBPIXEL:
antialias = ANTIALIAS_CLEARTYPE; break;
}
bool subpixel_order_is_vertical = false; if (antialias == ANTIALIAS_CLEARTYPE) { switch (subpixel_order) { case CAIRO_SUBPIXEL_ORDER_DEFAULT: case CAIRO_SUBPIXEL_ORDER_RGB: case CAIRO_SUBPIXEL_ORDER_BGR: break; case CAIRO_SUBPIXEL_ORDER_VRGB: case CAIRO_SUBPIXEL_ORDER_VBGR:
subpixel_order_is_vertical = true; break;
}
}
if (subpixel_order_is_vertical) { // DirectWrite does not support vertical pixel geometries. // As a workaround, apply a simmetry which swaps x and y // coordinates, then re-swap while copying the back into // the image surface
// swap the two rows
std::swap (matrix.m11, matrix.m21);
std::swap (matrix.m12, matrix.m22);
}
RefPtr<IDWriteGlyphRunAnalysis> dwrite_glyph_run_analysis; if (DWriteFactory::Instance3()) {
hr = DWriteFactory::Instance3()->CreateGlyphRunAnalysis(&run,
&matrix,
rendering_mode1,
scaled_font->measuring_mode,
grid_fit_mode,
text_antialias_mode, 0, // baselineOriginX, 0, // baselineOriginY,
&dwrite_glyph_run_analysis);
} elseif (DWriteFactory::Instance2()) {
hr = DWriteFactory::Instance2()->CreateGlyphRunAnalysis(&run,
&matrix,
rendering_mode,
scaled_font->measuring_mode,
grid_fit_mode,
text_antialias_mode, 0, // baselineOriginX, 0, // baselineOriginY,
&dwrite_glyph_run_analysis);
} else { if (antialias == ANTIALIAS_GRAY) { // IDWriteGlyphRunAnalysis supports gray-scale antialiasing only when // created from IDWriteFactory2 or later. If we have IDWriteFactory // only, fallback to rendering with Direct2D on A8 targets. return init_glyph_surface_fallback_a8 (scaled_font, scaled_glyph,
width, height, x1, y1, &matrix, &run);
}
unsignedchar *surface_data = cairo_image_surface_get_data (surface); int surface_stride = cairo_image_surface_get_stride (surface);
UINT32 dwrite_data_size;
BYTE *dwrite_data;
RECT dwrite_rect = { 0, // left 0, // top
width, // right
height // bottom
};
if (subpixel_order_is_vertical) {
std::swap (dwrite_rect.right,
dwrite_rect.bottom);
}
// Whether IDWriteGlyphRunAnalysis::CreateAlphaTexture() can render directly // on the cairo image surface (because the pixel formats match) or a separate // buffer is needed bool render_is_direct;
dwrite_data = (BYTE*) _cairo_malloc (dwrite_data_size); if (!dwrite_data) return CAIRO_INT_STATUS_UNSUPPORTED;
render_is_direct = false; break;
} case ANTIALIAS_GRAY:
{ // The image surface may have a stride that's bigger than width- // account for that by passing stride as width to DWrite. Note: // stride is a byte-size, but here pixel-size is exactly 1 byte.
dwrite_rect.right = cairo_image_surface_get_stride (surface);
// Most of the code here was copied and adapted from cairoft-font.c switch (antialias) { case ANTIALIAS_NONE:
{ unsignedchar *src = static_cast<unsignedchar*>(dwrite_data); unsignedchar *dst = surface_data;
for (int i = 0; i < height; i++) { unsignedchar *d = dst;
for (int k = 0; k < width % 8; k++) {
*d += (src[k] ? (1 << k) : 0);
}
d++;
src += (width % 8);
}
dst += surface_stride;
} break;
} case ANTIALIAS_GRAY:
{ // Nothing to do break;
} case ANTIALIAS_CLEARTYPE:
{ unsignedchar *src = static_cast<unsignedchar*>(dwrite_data); unsignedchar *dst = surface_data;
// The alpha channel is unused for component-alpha blending. // Here we set the alpha channel anyway so that things work // even in case of normal blending (but one likely gets some // color fringing)
switch (subpixel_order) { case CAIRO_SUBPIXEL_ORDER_DEFAULT: case CAIRO_SUBPIXEL_ORDER_RGB:
{ for (int i = 0; i < height; i++) {
UINT32 *d = reinterpret_cast<UINT32*>(dst);
RefPtr<IDWriteFontFace5> fontFace5; if (FAILED(dwritesf->dwriteface->QueryInterface(&fontFace5))) { /* If IDWriteFontFace5 is not available, assume this version of *DirectWritedoesnotsupportvariations.
*/
*is_synthetic = FALSE; return CAIRO_INT_STATUS_SUCCESS;
}
if (!fontFace5->HasVariations()) {
*is_synthetic = FALSE; return CAIRO_INT_STATUS_SUCCESS;
}
UINT32 axis_count = fontResource->GetFontAxisCount();
DWRITE_FONT_AXIS_VALUE *axis_defaults = new DWRITE_FONT_AXIS_VALUE[axis_count];
DWRITE_FONT_AXIS_VALUE *axis_values = new DWRITE_FONT_AXIS_VALUE[axis_count];
hr = fontResource->GetDefaultFontAxisValues(axis_defaults, axis_count); if (FAILED(hr)) {
status = _cairo_dwrite_error (hr, "GetDefaultFontAxisValues failed"); goto cleanup;
}
hr = fontFace5->GetFontAxisValues(axis_values, axis_count); if (FAILED(hr)) {
status = _cairo_dwrite_error (hr, "GetFontAxisValues failed"); goto cleanup;
}
/* The DirectWrite documentation does not state if the tags of the returned *defaultsandvaluesarraysareinthesameorder.Soassumetheyarenot.
*/
*is_synthetic = FALSE;
status = CAIRO_INT_STATUS_SUCCESS; for (UINT32 i = 0; i< axis_count; i++) { for (UINT32 j = 0; j < axis_count; j++) { if (axis_values[i].axisTag == axis_defaults[j].axisTag) { if (axis_values[i].value != axis_defaults[j].value) {
*is_synthetic = TRUE; goto cleanup;
} break;
}
}
}
/* Ensure IDWriteFactory4 is available before enabling color fonts */ if (DWriteFactory::Instance4()) {
RefPtr<IDWriteFontFace2> fontFace2; if (SUCCEEDED(dwriteface->QueryInterface(&fontFace2))) { if (fontFace2->IsColorFont())
face->have_color = true;
}
}
// XXX don't we need to set RenderingParams on this RenderTarget?
hr = rt->BindDC(surface->dc, &area); if (FAILED(hr)) return CAIRO_INT_STATUS_UNSUPPORTED;
// D2D uses 0x00RRGGBB not 0x00BBGGRR like COLORREF.
color = (color & 0xFF) << 16 |
(color & 0xFF00) |
(color & 0xFF0000) >> 16;
RefPtr<ID2D1SolidColorBrush> brush;
hr = rt->CreateSolidColorBrush(D2D1::ColorF(color, 1.0), &brush); if (FAILED(hr)) return CAIRO_INT_STATUS_UNSUPPORTED;
if (transform) {
rt->SetTransform(D2D1::Matrix3x2F(transform->m11,
transform->m12,
transform->m21,
transform->m22,
transform->dx,
transform->dy));
}
rt->BeginDraw();
rt->DrawGlyphRun(D2D1::Point2F(0, 0), run, brush);
hr = rt->EndDraw(); if (transform) {
rt->SetTransform(D2D1::Matrix3x2F::Identity());
} if (FAILED(hr)) return CAIRO_INT_STATUS_UNSUPPORTED;
return CAIRO_INT_STATUS_SUCCESS;
}
/* Surface helper function */
cairo_int_status_t
_cairo_dwrite_show_glyphs_on_surface(void *surface,
cairo_operator_t op, const cairo_pattern_t *source,
cairo_glyph_t *glyphs, int num_glyphs,
cairo_scaled_font_t *scaled_font,
cairo_clip_t *clip)
{ // TODO: Check font & surface for types.
cairo_dwrite_scaled_font_t *dwritesf = reinterpret_cast<cairo_dwrite_scaled_font_t*>(scaled_font);
cairo_win32_surface_t *dst = reinterpret_cast<cairo_win32_surface_t*>(surface);
cairo_int_status_t status;
/* We can only handle dwrite fonts */ if (cairo_scaled_font_get_type (scaled_font) != CAIRO_FONT_TYPE_DWRITE) return CAIRO_INT_STATUS_UNSUPPORTED;
/* We can only handle opaque solid color sources */ if (!_cairo_pattern_is_opaque_solid(source)) return CAIRO_INT_STATUS_UNSUPPORTED;
/* We can only handle operator SOURCE or OVER with the destination
* having no alpha */ if (op != CAIRO_OPERATOR_SOURCE && op != CAIRO_OPERATOR_OVER) return CAIRO_INT_STATUS_UNSUPPORTED;
/* It is vital that dx values for dxy_buf are calculated from the delta of *_logical_xcoordinates(notuserxcoordinates)orelsethesumofall *previousdxvaluesmaystarttodivergefromthecurrentglyph'sx *coordinateduetoaccumulatedroundingerror.Asaresultstringscould
* be painted shorter or longer than expected. */
#ifdef CAIRO_TRY_D2D_TO_GDI
status = _dwrite_draw_glyphs_to_gdi_surface_d2d(dst,
mat,
&run,
color,
copyArea);
if (status == (cairo_status_t)CAIRO_INT_STATUS_UNSUPPORTED) { #endif
status = _dwrite_draw_glyphs_to_gdi_surface_gdi(dst,
mat,
&run,
color,
dwritesf,
copyArea);
#ifdef CAIRO_TRY_D2D_TO_GDI
} #endif
return status;
}
/* Check if a specific font table in a DWrite font and a scaled font is identical */ static cairo_int_status_t
compare_font_tables (cairo_dwrite_font_face_t *dwface,
cairo_scaled_font_t *scaled_font, unsignedlong tag,
cairo_bool_t *match)
{ unsignedlong size;
cairo_int_status_t status; unsignedchar *buffer = NULL; constvoid *dw_data;
UINT32 dw_size; void *dw_tableContext = NULL; BOOL dw_exists = FALSE;
HRESULT hr;
cleanup:
free (buffer); if (dw_tableContext)
dwface->dwriteface->ReleaseFontTable(dw_tableContext);
return status;
}
/* Check if a DWrite font and a scaled font areis identical * *DWritedoesnotallowaccessingtheentirefontdatausingtag=0sowecompare *twoofthefonttables: *-'name'table *-'head'tablesincethiscontainsthechecksumfortheentirefont
*/ static cairo_int_status_t
font_tables_match (cairo_dwrite_font_face_t *dwface,
cairo_scaled_font_t *scaled_font,
cairo_bool_t *match)
{
cairo_int_status_t status;
status = compare_font_tables (dwface, scaled_font, TT_TAG_name, match); if (unlikely(status)) return status;
if (!*match) return CAIRO_INT_STATUS_SUCCESS;
status = compare_font_tables (dwface, scaled_font, TT_TAG_head, match); if (unlikely(status)) return status;
RefPtr<IDWriteGdiInterop> gdiInterop;
DWriteFactory::Instance()->GetGdiInterop(&gdiInterop); if (!gdiInterop) { return CAIRO_INT_STATUS_UNSUPPORTED;
}
/* TODO: use scaled font? */
LOGFONTW logfont; if (FAILED(gdiInterop->ConvertFontFaceToLOGFONT (dwface->dwriteface, &logfont))) { return CAIRO_INT_STATUS_UNSUPPORTED;
}
/* DWrite must have been using an outline font, so we want GDI to use the same, *evenifthere'salsoabitmapfaceavailable
*/
logfont.lfOutPrecision = OUT_OUTLINE_PRECIS;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.