// Helper function used in the implementation of ScriptItemize HRESULT PangoItemize(const char * chars, int cInChars, int cMaxItems, SCRIPT_ITEM *pItems, int * pcItems) { SCRIPT_CACHE context = NULL; PangoAttrList * attributes_list = pango_attr_list_new(); GList * items = pango_itemize(GetPangoContext(&context), chars, 0, cInChars, attributes_list, NULL); *pcItems = g_list_length(items); if (*pcItems >= cMaxItems) { pango_attr_list_unref(attributes_list); g_list_free(items); return E_OUTOFMEMORY; } for(int i = 0; i < *pcItems; ++i) { PangoItem* item = static_cast<PangoItem*>(g_list_nth_data(items, i)); pItems[i].iCharPos = item->offset; pItems[i].a.fRTL = item->analysis.level == 1; pItems[i].a.fLayoutRTL = pItems[i].a.fRTL; // TODO: set other fields in SCRIPT_ANALYSIS as needed. pango_item_free(item); } pango_attr_list_unref(attributes_list); g_list_free(items); return S_OK; }
// Helper function used in the implementation of ScriptShape HRESULT PangoCharsToGlyph(SCRIPT_CACHE *psc, const char * chars, int cInChars, int cMaxItems, PangoGlyphString **pGlpyhs, int * pcItems) { ScriptCacheImplementation * cache = reinterpret_cast<ScriptCacheImplementation*>(*psc); PangoContext * pangoContext; cache->m_vwGraphics->GetTextStyleContext(reinterpret_cast<HDC*>(&pangoContext)); PangoAttrList * attributes_list = pango_attr_list_new(); GList * items = pango_itemize(pangoContext, chars, 0, cInChars, attributes_list, NULL); int length = g_list_length(items); int glyphsCount = 0; pGlpyhs[0] = NULL; for(int i = 0; i < length; ++i) { PangoItem* item = static_cast<PangoItem*>(g_list_nth_data(items, i)); PangoGlyphString * ptrPangoGlyphString = pango_glyph_string_new(); pango_shape(chars + item->offset, item->length, &item->analysis, ptrPangoGlyphString); glyphsCount += ptrPangoGlyphString->num_glyphs; if (glyphsCount > cMaxItems) { pango_glyph_string_free(ptrPangoGlyphString); FreeGlyphs(reinterpret_cast<WORD*>(pGlpyhs), cMaxItems); pango_item_free(item); pango_attr_list_unref(attributes_list); g_list_free(items); return E_OUTOFMEMORY; } pGlpyhs[i] = ptrPangoGlyphString; if (i < (cMaxItems - 1)) pGlpyhs[i + 1] = NULL; // null term the list (used for deleting etc.) pango_item_free(item); } pango_attr_list_unref(attributes_list); g_list_free(items); *pcItems = glyphsCount; return S_OK; }
void FontSupport::drawText(const WFont& font, const WRectF& rect, const WTransform& transform, Bitmap& bitmap, WFlags<AlignmentFlag> flags, const WString& text) { PANGO_LOCK; enabledFontFormats = enabledFontFormats_; PangoMatrix matrix; matrix.xx = transform.m11(); matrix.xy = transform.m21(); matrix.yx = transform.m12(); matrix.yy = transform.m22(); matrix.x0 = transform.dx(); matrix.y0 = transform.dy(); std::string utf8 = text.toUTF8(); std::vector<PangoGlyphString *> glyphs; int width; pango_context_set_matrix(context_, &matrix); /* * Oh my god, somebody explain me why we need to do this... */ WFont f = font; f.setSize(font.sizeLength().toPixels() / pango_matrix_get_font_scale_factor(&matrix)); GList *items = layoutText(f, utf8, glyphs, width); pango_context_set_matrix(context_, nullptr); AlignmentFlag hAlign = flags & AlignHorizontalMask; /* FIXME handle bidi ! */ double x; switch (hAlign) { case AlignmentFlag::Left: x = rect.left(); break; case AlignmentFlag::Right: x = rect.right() - pangoUnitsToDouble(width); break; case AlignmentFlag::Center: x = rect.center().x() - pangoUnitsToDouble(width/2); break; default: x = 0; } AlignmentFlag vAlign = flags & AlignVerticalMask; PangoFont *pangoFont = matchFont(font).pangoFont(); PangoFontMetrics *metrics = pango_font_get_metrics(pangoFont, nullptr); double ascent = pangoUnitsToDouble(pango_font_metrics_get_ascent(metrics)); double descent = pangoUnitsToDouble(pango_font_metrics_get_descent(metrics)); pango_font_metrics_unref(metrics); double baseline = ascent; double height = ascent + descent; double y; switch (vAlign) { case AlignmentFlag::Top: y = rect.top() + baseline; break; case AlignmentFlag::Middle: y = rect.center().y() - height / 2 + baseline; break; case AlignmentFlag::Bottom: y = rect.bottom() - height + baseline; break; default: y = 0; } FT_Bitmap bmp; bmp.buffer = bitmap.buffer(); bmp.width = bitmap.width(); bmp.rows = bitmap.height(); bmp.pitch = bitmap.pitch(); bmp.pixel_mode = FT_PIXEL_MODE_GRAY; bmp.num_grays = 16; // ??? GList *elem; unsigned i = 0; for (elem = items; elem; elem = elem->next) { PangoItem *item = (PangoItem *)elem->data; PangoAnalysis *analysis = &item->analysis; PangoGlyphString *gl = glyphs[i++]; pango_ft2_render_transformed(&bmp, &matrix, analysis->font, gl, pangoUnitsFromDouble(x), pangoUnitsFromDouble(y)); x += pangoUnitsToDouble(pango_glyph_string_get_width(gl)); pango_glyph_string_free(gl); pango_item_free(item); } g_list_free(items); }
void FontSupport::drawText(const WFont& font, const WRectF& rect, WFlags<AlignmentFlag> flags, const WString& text) { PANGO_LOCK; enabledFontFormats = enabledFontFormats_; std::string utf8 = text.toUTF8(); std::vector<PangoGlyphString *> glyphs; int width; GList *items = layoutText(font, utf8, glyphs, width); AlignmentFlag hAlign = flags & AlignHorizontalMask; AlignmentFlag vAlign = flags & AlignVerticalMask; /* FIXME handle bidi ! */ double x; switch (hAlign) { case AlignmentFlag::Left: x = rect.left(); break; case AlignmentFlag::Right: x = rect.right() - pangoUnitsToDouble(width); break; case AlignmentFlag::Center: x = rect.center().x() - pangoUnitsToDouble(width/2); break; default: x = 0; } unsigned i = 0; for (GList *elem = items; elem; elem = elem->next) { PangoItem *item = (PangoItem *)elem->data; PangoAnalysis *analysis = &item->analysis; PangoGlyphString *gl = glyphs[i++]; currentFont_ = analysis->font; /* * Note, we are actually ignoring the selected glyphs here, which * is a pitty and possibly wrong if the device does not make the * same selection ! */ WString s = WString::fromUTF8(utf8.substr(item->offset, item->length)); device_->drawText(WRectF(x, rect.y(), 1000, rect.height()), AlignmentFlag::Left | vAlign, TextFlag::SingleLine, s, nullptr); WTextItem textItem = device_->measureText(s, -1, false); x += textItem.width(); pango_item_free(item); pango_glyph_string_free(gl); } g_list_free(items); currentFont_ = nullptr; }
/* Shapes the ellipsis using the font and is_cjk information computed by * update_ellipsis_shape() from the first character in the gap. */ static void shape_ellipsis (EllipsizeState *state) { PangoAttrList *attrs = pango_attr_list_new (); GSList *run_attrs; PangoItem *item; PangoGlyphString *glyphs; GSList *l; PangoAttribute *fallback; const char *ellipsis_text; int i; /* Create/reset state->ellipsis_run */ if (!state->ellipsis_run) { state->ellipsis_run = g_slice_new (PangoGlyphItem); state->ellipsis_run->glyphs = pango_glyph_string_new (); state->ellipsis_run->item = NULL; } if (state->ellipsis_run->item) { pango_item_free (state->ellipsis_run->item); state->ellipsis_run->item = NULL; } /* Create an attribute list */ run_attrs = pango_attr_iterator_get_attrs (state->gap_start_attr); for (l = run_attrs; l; l = l->next) { PangoAttribute *attr = l->data; attr->start_index = 0; attr->end_index = G_MAXINT; pango_attr_list_insert (attrs, attr); } g_slist_free (run_attrs); fallback = pango_attr_fallback_new (FALSE); fallback->start_index = 0; fallback->end_index = G_MAXINT; pango_attr_list_insert (attrs, fallback); /* First try using a specific ellipsis character in the best matching font */ if (state->ellipsis_is_cjk) ellipsis_text = "\342\213\257"; /* U+22EF: MIDLINE HORIZONTAL ELLIPSIS, used for CJK */ else ellipsis_text = "\342\200\246"; /* U+2026: HORIZONTAL ELLIPSIS */ item = itemize_text (state, ellipsis_text, attrs); /* If that fails we use "..." in the first matching font */ if (!item->analysis.font || !_pango_engine_shape_covers (item->analysis.shape_engine, item->analysis.font, item->analysis.language, g_utf8_get_char (ellipsis_text))) { pango_item_free (item); /* Modify the fallback iter while it is inside the PangoAttrList; Don't try this at home */ ((PangoAttrInt *)fallback)->value = TRUE; ellipsis_text = "..."; item = itemize_text (state, ellipsis_text, attrs); } pango_attr_list_unref (attrs); state->ellipsis_run->item = item; /* Now shape */ glyphs = state->ellipsis_run->glyphs; pango_shape (ellipsis_text, strlen (ellipsis_text), &item->analysis, glyphs); state->ellipsis_width = 0; for (i = 0; i < glyphs->num_glyphs; i++) state->ellipsis_width += glyphs->glyphs[i].geometry.width; }