static VALUE rg_get_glyph_extents(VALUE self, VALUE glyph) { PangoRectangle ink_rect, logical_rect; pango_font_get_glyph_extents(_SELF(self), NUM2UINT(glyph), &ink_rect, &logical_rect); return rb_assoc_new(PANGORECTANGLE2RVAL(&ink_rect), PANGORECTANGLE2RVAL(&logical_rect)); }
static void set_glyph (PangoFont *font, PangoGlyphString *glyphs, int i, int offset, PangoGlyph glyph) { PangoRectangle logical_rect; glyphs->glyphs[i].glyph = glyph; glyphs->glyphs[i].geometry.x_offset = 0; glyphs->glyphs[i].geometry.y_offset = 0; glyphs->log_clusters[i] = offset; pango_font_get_glyph_extents (font, glyphs->glyphs[i].glyph, NULL, &logical_rect); glyphs->glyphs[i].geometry.width = logical_rect.width; }
static void set_glyph_tone (PangoFont *font, PangoGlyphString *glyphs, int i, int offset, PangoGlyph glyph) { PangoRectangle logical_rect, ink_rect; PangoRectangle logical_rect_cluster; glyphs->glyphs[i].glyph = glyph; glyphs->glyphs[i].geometry.y_offset = 0; glyphs->log_clusters[i] = offset; pango_font_get_glyph_extents (font, glyphs->glyphs[i].glyph, &ink_rect, &logical_rect); /* tone mark is not the first in a glyph string. We have info. on the * preceding glyphs in a glyph string */ { int j = i - 1; /* search for the beg. of the preceding cluster */ while (j >= 0 && glyphs->log_clusters[j] == glyphs->log_clusters[i - 1]) j--; /* In .._extents_range(...,start,end,...), to my surprise start is * inclusive but end is exclusive !! */ pango_glyph_string_extents_range (glyphs, j + 1, i, font, NULL, &logical_rect_cluster); /* logical_rect_cluster.width is all the offset we need so that the * inherent x_offset in the glyph (ink_rect.x) should be canceled out. */ glyphs->glyphs[i].geometry.x_offset = - logical_rect_cluster.width - ink_rect.x ; /* make an additional room for a tone mark if it has a spacing glyph * because that's likely to be an indication that glyphs for other * characters in the font are not designed for combining with tone marks. */ if (logical_rect.width) { glyphs->glyphs[i].geometry.x_offset -= ink_rect.width; glyphs->glyphs[j + 1].geometry.width += ink_rect.width; glyphs->glyphs[j + 1].geometry.x_offset += ink_rect.width; } } glyphs->glyphs[i].geometry.width = 0; }
void _pango_cairo_font_private_get_glyph_extents (PangoCairoFontPrivate *cf_priv, PangoGlyph glyph, PangoRectangle *ink_rect, PangoRectangle *logical_rect) { PangoCairoFontGlyphExtentsCacheEntry *entry; if (!cf_priv || (cf_priv->glyph_extents_cache == NULL && !_pango_cairo_font_private_glyph_extents_cache_init (cf_priv))) { /* Get generic unknown-glyph extents. */ pango_font_get_glyph_extents (NULL, glyph, ink_rect, logical_rect); return; } if (glyph == PANGO_GLYPH_EMPTY) { if (ink_rect) ink_rect->x = ink_rect->y = ink_rect->width = ink_rect->height = 0; if (logical_rect) *logical_rect = cf_priv->font_extents; return; } else if (glyph & PANGO_GLYPH_UNKNOWN_FLAG) { _pango_cairo_font_private_get_glyph_extents_missing(cf_priv, glyph, ink_rect, logical_rect); return; } entry = _pango_cairo_font_private_get_glyph_extents_cache_entry (cf_priv, glyph); if (ink_rect) *ink_rect = entry->ink_rect; if (logical_rect) { *logical_rect = cf_priv->font_extents; logical_rect->width = entry->width; } }
static void _pango_cairo_font_private_get_glyph_extents_missing (PangoCairoFontPrivate *cf_priv, PangoGlyph glyph, PangoRectangle *ink_rect, PangoRectangle *logical_rect) { PangoCairoFontHexBoxInfo *hbi; gunichar ch; gint rows, cols; hbi = _pango_cairo_font_private_get_hex_box_info (cf_priv); if (!hbi) { pango_font_get_glyph_extents (NULL, glyph, ink_rect, logical_rect); return; } ch = glyph & ~PANGO_GLYPH_UNKNOWN_FLAG; rows = hbi->rows; if (G_UNLIKELY (glyph == PANGO_GLYPH_INVALID_INPUT || ch > 0x10FFFF)) cols = 1; else cols = ((glyph & ~PANGO_GLYPH_UNKNOWN_FLAG) > 0xffff ? 6 : 4) / rows; if (ink_rect) { ink_rect->x = PANGO_SCALE * hbi->pad_x; ink_rect->y = PANGO_SCALE * (hbi->box_descent - hbi->box_height); ink_rect->width = PANGO_SCALE * (3 * hbi->pad_x + cols * (hbi->digit_width + hbi->pad_x)); ink_rect->height = PANGO_SCALE * hbi->box_height; } if (logical_rect) { logical_rect->x = 0; logical_rect->y = PANGO_SCALE * (hbi->box_descent - (hbi->box_height + hbi->pad_y)); logical_rect->width = PANGO_SCALE * (5 * hbi->pad_x + cols * (hbi->digit_width + hbi->pad_x)); logical_rect->height = PANGO_SCALE * (hbi->box_height + 2 * hbi->pad_y); } }
bool PangoFontInfo::GetSpacingProperties(const string& utf8_char, int* x_bearing, int* x_advance) const { // Convert to equivalent PangoFont structure PangoFont* font = ToPangoFont(); // Find the glyph index in the font for the supplied utf8 character. int total_advance = 0; int min_bearing = 0; // Handle multi-unicode strings by reporting the left-most position of the // x-bearing, and right-most position of the x-advance if the string were to // be rendered. const UNICHAR::const_iterator it_begin = UNICHAR::begin(utf8_char.c_str(), utf8_char.length()); const UNICHAR::const_iterator it_end = UNICHAR::end(utf8_char.c_str(), utf8_char.length()); for (UNICHAR::const_iterator it = it_begin; it != it_end; ++it) { PangoGlyph glyph_index = pango_fc_font_get_glyph( reinterpret_cast<PangoFcFont*>(font), *it); if (!glyph_index) { // Glyph for given unicode character doesn't exist in font. return false; } // Find the ink glyph extents for the glyph PangoRectangle ink_rect, logical_rect; pango_font_get_glyph_extents(font, glyph_index, &ink_rect, &logical_rect); pango_extents_to_pixels(&ink_rect, NULL); pango_extents_to_pixels(&logical_rect, NULL); int bearing = total_advance + PANGO_LBEARING(ink_rect); if (it == it_begin || bearing < min_bearing) { min_bearing = bearing; } total_advance += PANGO_RBEARING(logical_rect); } *x_bearing = min_bearing; *x_advance = total_advance; return true; }
/** * pango_glyph_string_extents_range: * @glyphs: a #PangoGlyphString * @start: start index * @end: end index (the range is the set of bytes with indices such that start <= index < end) * @font: a #PangoFont * @ink_rect: rectangle used to store the extents of the glyph string range as drawn * or %NULL to indicate that the result is not needed. * @logical_rect: rectangle used to store the logical extents of the glyph string range * or %NULL to indicate that the result is not needed. * * Computes the extents of a sub-portion of a glyph string. The extents are * relative to the start of the glyph string range (the origin of their * coordinate system is at the start of the range, not at the start of the entire * glyph string). **/ void pango_glyph_string_extents_range (PangoGlyphString *glyphs, int start, int end, PangoFont *font, PangoRectangle *ink_rect, PangoRectangle *logical_rect) { int x_pos = 0; int i; /* Note that the handling of empty rectangles for ink * and logical rectangles is different. A zero-height ink * rectangle makes no contribution to the overall ink rect, * while a zero-height logical rect still reserves horizontal * width. Also, we may return zero-width, positive height * logical rectangles, while we'll never do that for the * ink rect. */ g_return_if_fail (start <= end); if (G_UNLIKELY (!ink_rect && !logical_rect)) return; if (ink_rect) { ink_rect->x = 0; ink_rect->y = 0; ink_rect->width = 0; ink_rect->height = 0; } if (logical_rect) { logical_rect->x = 0; logical_rect->y = 0; logical_rect->width = 0; logical_rect->height = 0; } for (i = start; i < end; i++) { PangoRectangle glyph_ink; PangoRectangle glyph_logical; PangoGlyphGeometry *geometry = &glyphs->glyphs[i].geometry; pango_font_get_glyph_extents (font, glyphs->glyphs[i].glyph, ink_rect ? &glyph_ink : NULL, logical_rect ? &glyph_logical : NULL); if (ink_rect && glyph_ink.width != 0 && glyph_ink.height != 0) { if (ink_rect->width == 0 || ink_rect->height == 0) { ink_rect->x = x_pos + glyph_ink.x + geometry->x_offset; ink_rect->width = glyph_ink.width; ink_rect->y = glyph_ink.y + geometry->y_offset; ink_rect->height = glyph_ink.height; } else { int new_x, new_y; new_x = MIN (ink_rect->x, x_pos + glyph_ink.x + geometry->x_offset); ink_rect->width = MAX (ink_rect->x + ink_rect->width, x_pos + glyph_ink.x + glyph_ink.width + geometry->x_offset) - new_x; ink_rect->x = new_x; new_y = MIN (ink_rect->y, glyph_ink.y + geometry->y_offset); ink_rect->height = MAX (ink_rect->y + ink_rect->height, glyph_ink.y + glyph_ink.height + geometry->y_offset) - new_y; ink_rect->y = new_y; } } if (logical_rect) { logical_rect->width += geometry->width; if (i == start) { logical_rect->y = glyph_logical.y; logical_rect->height = glyph_logical.height; } else { int new_y = MIN (logical_rect->y, glyph_logical.y); logical_rect->height = MAX (logical_rect->y + logical_rect->height, glyph_logical.y + glyph_logical.height) - new_y; logical_rect->y = new_y; } } x_pos += geometry->width; } }
TGlyphInfo *glyph_cache_get_info(TGlyphCache *cache, gunichar glyph) { TGlyphInfo *gfi; XftFont *xftfont; PangoFont *font; PangoGlyph pglyph; PangoRectangle ink, logical; gint ascent, descent; gint x_offset; gint nominal_width; double scale_y, scale_x; if (!cache->hash) return NULL; gfi = g_hash_table_lookup(cache->hash, GINT_TO_POINTER(glyph)); if (gfi) return gfi; font = pango_fontset_get_font(cache->font_set, glyph); pglyph = pango_fc_font_get_glyph(PANGO_FC_FONT(font), glyph); if (!pglyph) { fprintf (stderr, "Error: Unable to find glyph %d.\n", glyph); if (!pglyph) pglyph = pango_fc_font_get_glyph(PANGO_FC_FONT(font), glyph); if (!pglyph) pglyph = PANGO_GET_UNKNOWN_GLYPH (glyph); if (!pglyph) return NULL; } pango_font_get_glyph_extents(font, pglyph, &ink, &logical); ascent = PANGO_ASCENT(logical); descent = PANGO_DESCENT(logical); xftfont = pango_xft_font_get_font(font); x_offset = 0; nominal_width = cache->width; if (g_unichar_iswide(glyph)) nominal_width *= 2; scale_x = scale_y = 1.0; if (logical.width > nominal_width) { if (logical.width) scale_x = (double)nominal_width / (double)logical.width; else scale_x = 1.0; } if (logical.height != cache->height) { double scale; if (ascent) { scale_y = (double)cache->ascent / (double)ascent; } else { scale_y = 1.0; } if (descent) { scale = (double)cache->descent / (double)descent; if (scale < scale_y) scale_y = scale; } } if (scale_x >= 1.0) { scale_x = 1.0; x_offset += (nominal_width - logical.width) / 2; } if (scale_x < 1.0 || scale_y != 1.0) { FcBool scalable; FcPatternGetBool(xftfont->pattern, FC_SCALABLE, 0, &scalable); if (!scalable) { /* Bah. Need better handling of non-scalable fonts */ if (scale_x < 1.0) scale_x = 1.0; scale_y = 1.0; } else if (scale_x < 1.0 || scale_y != 1.0) { FcPattern *pattern; FcMatrix mat; pattern = FcPatternDuplicate(xftfont->pattern); FcMatrixInit (&mat); FcMatrixScale(&mat, scale_x, scale_y); FcPatternDel (pattern, FC_MATRIX); FcPatternAddMatrix(pattern, FC_MATRIX, &mat); xftfont = XftFontOpenPattern( GDK_DISPLAY_XDISPLAY(cache->display), pattern ); } ascent = ascent * scale_y; } g_object_unref(font); // gfi = calloc(sizeof(TGlyphInfo), 1); gfi = g_slice_new(TGlyphInfo); gfi->font = xftfont; gfi->x_offset = PANGO_PIXELS(x_offset); gfi->y_offset = cache->ascent + (cache->ascent - ascent); gfi->y_offset = PANGO_PIXELS(gfi->y_offset); g_hash_table_insert(cache->hash, GINT_TO_POINTER(glyph), gfi); return gfi; }
static gboolean itemize_shape_and_place (PangoFont *font, HDC hdc, wchar_t *wtext, int wlen, const PangoAnalysis *analysis, PangoGlyphString *glyphs) { int i; int item, nitems, item_step; int itemlen, glyphix, nglyphs; SCRIPT_CONTROL control; SCRIPT_STATE state; SCRIPT_ITEM items[100]; double scale = pango_win32_font_get_metrics_factor (font); HFONT hfont = _pango_win32_font_get_hfont (font); static GHashTable *script_cache_hash = NULL; if (!script_cache_hash) script_cache_hash = g_hash_table_new (g_int64_hash, g_int64_equal); memset (&control, 0, sizeof (control)); memset (&state, 0, sizeof (state)); control.uDefaultLanguage = make_langid (analysis->language); state.uBidiLevel = analysis->level; #ifdef BASIC_WIN32_DEBUGGING if (pango_win32_debug) g_print (G_STRLOC ": ScriptItemize: uDefaultLanguage:%04x uBidiLevel:%d\n", control.uDefaultLanguage, state.uBidiLevel); #endif if (ScriptItemize (wtext, wlen, G_N_ELEMENTS (items), &control, NULL, items, &nitems)) { #ifdef BASIC_WIN32_DEBUGGING if (pango_win32_debug) g_print ("ScriptItemize failed\n"); #endif return FALSE; } #ifdef BASIC_WIN32_DEBUGGING if (pango_win32_debug) g_print ("%d items:\n", nitems); #endif if (analysis->level % 2) { item = nitems - 1; item_step = -1; } else { item = 0; item_step = 1; } for (i = 0; i < nitems; i++, item += item_step) { WORD iglyphs[1000]; WORD log_clusters[1000]; SCRIPT_VISATTR visattrs[1000]; int advances[1000]; GOFFSET offsets[1000]; ABC abc; gint32 script = items[item].a.eScript; int ng; int char_offset; SCRIPT_CACHE *script_cache; gint64 font_and_script_key; memset (advances, 0, sizeof (advances)); memset (offsets, 0, sizeof (offsets)); memset (&abc, 0, sizeof (abc)); /* Note that itemlen is number of wchar_t's i.e. surrogate pairs * count as two! */ itemlen = items[item+1].iCharPos - items[item].iCharPos; char_offset = items[item].iCharPos; #ifdef BASIC_WIN32_DEBUGGING if (pango_win32_debug) g_print (" Item %d: iCharPos=%d eScript=%d (%s) %s%s%s%s%s%s%s wchar_t %d--%d (%d)\n", item, items[item].iCharPos, script, lang_name (scripts[script]->langid), scripts[script]->fComplex ? "complex" : "simple", items[item].a.fRTL ? " fRTL" : "", items[item].a.fLayoutRTL ? " fLayoutRTL" : "", items[item].a.fLinkBefore ? " fLinkBefore" : "", items[item].a.fLinkAfter ? " fLinkAfter" : "", items[item].a.fLogicalOrder ? " fLogicalOrder" : "", items[item].a.fNoGlyphIndex ? " fNoGlyphIndex" : "", items[item].iCharPos, items[item+1].iCharPos-1, itemlen); #endif /* Create a hash key based on hfont and script engine */ font_and_script_key = (((gint64) ((gint32) hfont)) << 32) | script; /* Get the script cache for this hfont and script */ script_cache = g_hash_table_lookup (script_cache_hash, &font_and_script_key); if (!script_cache) { gint64 *key_n; SCRIPT_CACHE *new_script_cache; key_n = g_new (gint64, 1); *key_n = font_and_script_key; new_script_cache = g_new0 (SCRIPT_CACHE, 1); script_cache = new_script_cache; /* Insert the new value */ g_hash_table_insert (script_cache_hash, key_n, new_script_cache); #ifdef BASIC_WIN32_DEBUGGING if (pango_win32_debug) g_print (" New SCRIPT_CACHE for font %p and script %d\n", hfont, script); #endif } items[item].a.fRTL = analysis->level % 2; if (ScriptShape (hdc, script_cache, wtext + items[item].iCharPos, itemlen, G_N_ELEMENTS (iglyphs), &items[item].a, iglyphs, log_clusters, visattrs, &nglyphs)) { #ifdef BASIC_WIN32_DEBUGGING if (pango_win32_debug) g_print ("pango-basic-win32: ScriptShape failed\n"); #endif return FALSE; } #ifdef BASIC_WIN32_DEBUGGING dump_glyphs_and_log_clusters (items[item].a.fRTL, itemlen, items[item].iCharPos, log_clusters, iglyphs, nglyphs); #endif ng = glyphs->num_glyphs; pango_glyph_string_set_size (glyphs, ng + nglyphs); set_up_pango_log_clusters (wtext + items[item].iCharPos, items[item].a.fRTL, itemlen, log_clusters, nglyphs, glyphs->log_clusters + ng, char_offset); if (ScriptPlace (hdc, script_cache, iglyphs, nglyphs, visattrs, &items[item].a, advances, offsets, &abc)) { #ifdef BASIC_WIN32_DEBUGGING if (pango_win32_debug) g_print ("pango-basic-win32: ScriptPlace failed\n"); #endif return FALSE; } for (glyphix = 0; glyphix < nglyphs; glyphix++) { if (iglyphs[glyphix] != 0) { glyphs->glyphs[ng+glyphix].glyph = iglyphs[glyphix]; glyphs->glyphs[ng+glyphix].geometry.width = floor (0.5 + scale * advances[glyphix]); glyphs->glyphs[ng+glyphix].geometry.x_offset = floor (0.5 + scale * offsets[glyphix].du); glyphs->glyphs[ng+glyphix].geometry.y_offset = floor (0.5 + scale * offsets[glyphix].dv); } else { PangoRectangle logical_rect; /* Should pass actual char that was not found to * PANGO_GET_UNKNOWN_GLYPH(), but a bit hard to * find out that at this point, so cheat and use 0. */ PangoGlyph unk = PANGO_GET_UNKNOWN_GLYPH (0); glyphs->glyphs[ng+glyphix].glyph = unk; pango_font_get_glyph_extents (font, unk, NULL, &logical_rect); glyphs->glyphs[ng+glyphix].geometry.width = logical_rect.width; glyphs->glyphs[ng+glyphix].geometry.x_offset = 0; glyphs->glyphs[ng+glyphix].geometry.y_offset = 0; } } } #ifdef BASIC_WIN32_DEBUGGING if (pango_win32_debug) { g_print (" Pango log_clusters (level:%d), char index:", analysis->level); for (glyphix = 0; glyphix < glyphs->num_glyphs; glyphix++) g_print ("%d ", glyphs->log_clusters[glyphix]); g_print ("\n"); } #endif return TRUE; }
void doDrawGlyphs(PangoRenderer* renderer, PangoFont* font, PangoGlyphString* glyphs, int px, int py) { Renderer* ren = RENDERER(renderer); if (!ren->m_runs) return; std::vector<ViewdoTextRun>& runs = *(ren->m_runs); const float s = ren->m_scale; PangoColor* fg = pango_renderer_get_color(renderer, PANGO_RENDER_PART_FOREGROUND); //PangoColor* bg = pango_renderer_get_color(renderer, PANGO_RENDER_PART_BACKGROUND); float red = !fg ? 0.0f : fg->red / 65536.0f; float green = !fg ? 0.0f : fg->green / 65536.0f; float blue = !fg ? 0.0f : fg->blue / 65536.0f; PangoFontDescription* desc = pango_font_describe(font); unsigned int fontHash = pango_font_description_hash(desc); pango_font_description_free(desc); FT_Face face = pango_fc_font_lock_face((PangoFcFont*) font); PangoGlyphUnit layoutX = px; PangoGlyphUnit layoutY = py; ViewdoGlyphCache& cache = ViewdoGlyphCache::instance(); for (int i = 0; i < glyphs->num_glyphs; i++) { PangoGlyphInfo* gi = glyphs->glyphs + i; if (gi->glyph & PANGO_GLYPH_UNKNOWN_FLAG) { // XXX: Draw the fallback square. continue; } unsigned int glyph = gi->glyph; PangoRectangle r; pango_font_get_glyph_extents(font, glyph, &r, 0); pango_extents_to_pixels(&r, 0); float w = r.width; float h = r.height; if (w <= 0.f && h <= 0.f) { // Space. layoutX += gi->geometry.width; continue; } // Load and render the glyph. We probably need to just tell the font to cache it // and then grab the coordinates of it. const ViewdoGlyph& cachedGlyph = cache.findOrCreate(gi->glyph, fontHash, face); // Walk our existing runs and try to find one with the same color and page. // XXX: Fastpath try and use the run from the last glyph. ViewdoTextRun* run = nullptr; for (auto i = runs.begin(); i != runs.end(); i++) { if (i->m_page == cachedGlyph.m_page && i->m_red == red && i->m_green == green && i->m_blue == blue) { run = &(*i); break; } } if (!run) { runs.push_back(ViewdoTextRun(cachedGlyph.m_page, red, green, blue)); run = &(runs[runs.size() - 1]); } float x = PANGO_PIXELS(layoutX + gi->geometry.x_offset) + cachedGlyph.m_offsetLeft; float y = PANGO_PIXELS(layoutY + gi->geometry.y_offset) - cachedGlyph.m_offsetTop; // Append ourselves onto this run. addPoint(run->m_geometry, x, y, cachedGlyph.m_x0, cachedGlyph.m_y0, s); addPoint(run->m_geometry, x + cachedGlyph.m_width, y, cachedGlyph.m_x1, cachedGlyph.m_y0, s); addPoint(run->m_geometry, x, y + cachedGlyph.m_height, cachedGlyph.m_x0, cachedGlyph.m_y1, s); // Triangle 2. addPoint(run->m_geometry, x + cachedGlyph.m_width, y, cachedGlyph.m_x1, cachedGlyph.m_y0, s); addPoint(run->m_geometry, x, y + cachedGlyph.m_height, cachedGlyph.m_x0, cachedGlyph.m_y1, s); addPoint(run->m_geometry, x + cachedGlyph.m_width, y + cachedGlyph.m_height, cachedGlyph.m_x1, cachedGlyph.m_y1, s); layoutX += gi->geometry.width; } pango_fc_font_unlock_face((PangoFcFont*) font); }
/** * pango_ot_buffer_output * @buffer: a #PangoOTBuffer * @glyphs: a #PangoGlyphString * * Exports the glyphs in a #PangoOTBuffer into a #PangoGlyphString. This is * typically used after the OpenType layout processing is over, to convert the * resulting glyphs into a generic Pango glyph string. * * Since: 1.4 **/ void pango_ot_buffer_output (PangoOTBuffer *buffer, PangoGlyphString *glyphs) { FT_Face face; PangoOTInfo *info; HB_GDEF gdef = NULL; unsigned int i; int last_cluster; face = pango_fc_font_lock_face (buffer->font); g_assert (face); /* Copy glyphs into output glyph string */ pango_glyph_string_set_size (glyphs, buffer->buffer->in_length); last_cluster = -1; for (i = 0; i < buffer->buffer->in_length; i++) { HB_GlyphItem item = &buffer->buffer->in_string[i]; glyphs->glyphs[i].glyph = item->gindex; glyphs->log_clusters[i] = item->cluster; if (glyphs->log_clusters[i] != last_cluster) glyphs->glyphs[i].attr.is_cluster_start = 1; else glyphs->glyphs[i].attr.is_cluster_start = 0; last_cluster = glyphs->log_clusters[i]; } info = pango_ot_info_get (face); gdef = pango_ot_info_get_gdef (info); /* Apply default positioning */ for (i = 0; i < (unsigned int)glyphs->num_glyphs; i++) { if (glyphs->glyphs[i].glyph) { PangoRectangle logical_rect; FT_UShort property; if (buffer->zero_width_marks && gdef && HB_GDEF_Get_Glyph_Property (gdef, glyphs->glyphs[i].glyph, &property) == FT_Err_Ok && (property == HB_GDEF_MARK || (property & HB_LOOKUP_FLAG_IGNORE_SPECIAL_MARKS) != 0)) { glyphs->glyphs[i].geometry.width = 0; } else { pango_font_get_glyph_extents ((PangoFont *)buffer->font, glyphs->glyphs[i].glyph, NULL, &logical_rect); glyphs->glyphs[i].geometry.width = logical_rect.width; } } else glyphs->glyphs[i].geometry.width = 0; glyphs->glyphs[i].geometry.x_offset = 0; glyphs->glyphs[i].geometry.y_offset = 0; } if (buffer->rtl) { /* Swap all glyphs */ swap_range (glyphs, 0, glyphs->num_glyphs); } if (buffer->applied_gpos) { if (buffer->rtl) apply_gpos_rtl (glyphs, buffer->buffer->positions); else apply_gpos_ltr (glyphs, buffer->buffer->positions); } else pango_fc_font_kern_glyphs (buffer->font, glyphs); pango_fc_font_unlock_face (buffer->font); }
static PangoClutterGlyphCacheValue * pango_clutter_renderer_get_cached_glyph (PangoRenderer *renderer, PangoFont *font, PangoGlyph glyph) { PangoClutterRenderer *priv = PANGO_CLUTTER_RENDERER (renderer); PangoClutterGlyphCacheValue *value; PangoClutterGlyphCache *glyph_cache; glyph_cache = priv->use_mipmapping ? priv->mipmapped_glyph_cache : priv->glyph_cache; if ((value = pango_clutter_glyph_cache_lookup (glyph_cache, font, glyph)) == NULL) { cairo_surface_t *surface; cairo_t *cr; cairo_scaled_font_t *scaled_font; PangoRectangle ink_rect; cairo_glyph_t cairo_glyph; pango_font_get_glyph_extents (font, glyph, &ink_rect, NULL); pango_extents_to_pixels (&ink_rect, NULL); surface = cairo_image_surface_create (CAIRO_FORMAT_A8, ink_rect.width, ink_rect.height); cr = cairo_create (surface); scaled_font = pango_cairo_font_get_scaled_font (PANGO_CAIRO_FONT (font)); cairo_set_scaled_font (cr, scaled_font); cairo_glyph.x = -ink_rect.x; cairo_glyph.y = -ink_rect.y; /* The PangoCairo glyph numbers directly map to Cairo glyph numbers */ cairo_glyph.index = glyph; cairo_show_glyphs (cr, &cairo_glyph, 1); cairo_destroy (cr); cairo_surface_flush (surface); /* Copy the glyph to the cache */ value = pango_clutter_glyph_cache_set (glyph_cache, font, glyph, cairo_image_surface_get_data (surface), cairo_image_surface_get_width (surface), cairo_image_surface_get_height (surface), cairo_image_surface_get_stride (surface), ink_rect.x, ink_rect.y); cairo_surface_destroy (surface); CLUTTER_NOTE (PANGO, "cache fail %i", glyph); } else CLUTTER_NOTE (PANGO, "cache success %i", glyph); return value; }
CoglPangoGlyphCacheValue * cogl_pango_glyph_cache_lookup (CoglPangoGlyphCache *cache, CoglBool create, PangoFont *font, PangoGlyph glyph) { CoglPangoGlyphCacheKey lookup_key; CoglPangoGlyphCacheValue *value; lookup_key.font = font; lookup_key.glyph = glyph; value = g_hash_table_lookup (cache->hash_table, &lookup_key); if (create && value == NULL) { CoglPangoGlyphCacheKey *key; PangoRectangle ink_rect; value = g_slice_new (CoglPangoGlyphCacheValue); value->texture = NULL; pango_font_get_glyph_extents (font, glyph, &ink_rect, NULL); pango_extents_to_pixels (&ink_rect, NULL); value->draw_x = ink_rect.x; value->draw_y = ink_rect.y; value->draw_width = ink_rect.width; value->draw_height = ink_rect.height; /* If the glyph is zero-sized then we don't need to reserve any space for it and we can just avoid painting anything */ if (ink_rect.width < 1 || ink_rect.height < 1) value->dirty = FALSE; else { /* Try adding the glyph to the global atlas... */ if (!cogl_pango_glyph_cache_add_to_global_atlas (cache, font, glyph, value) && /* If it fails try the local atlas */ !cogl_pango_glyph_cache_add_to_local_atlas (cache, font, glyph, value)) { cogl_pango_glyph_cache_value_free (value); return NULL; } value->dirty = TRUE; cache->has_dirty_glyphs = TRUE; } key = g_slice_new (CoglPangoGlyphCacheKey); key->font = g_object_ref (font); key->glyph = glyph; g_hash_table_insert (cache->hash_table, key, value); } return value; }
static void basic_engine_shape (PangoEngineShape *engine, PangoFont *font, const char *text, gint length, PangoAnalysis *analysis, PangoGlyphString *glyphs) { int n_chars; int i; const char *p; g_return_if_fail (font != NULL); g_return_if_fail (text != NULL); g_return_if_fail (length >= 0); g_return_if_fail (analysis != NULL); #ifdef HAVE_USP10_H if (have_uniscribe && !text_is_simple (text, length) && uniscribe_shape (font, text, length, analysis, glyphs)) return; #endif n_chars = g_utf8_strlen (text, length); pango_glyph_string_set_size (glyphs, n_chars); p = text; for (i = 0; i < n_chars; i++) { gunichar wc; gunichar mirrored_ch; PangoGlyph index; wc = g_utf8_get_char (p); if (analysis->level % 2) if (pango_get_mirror_char (wc, &mirrored_ch)) wc = mirrored_ch; if (wc == 0xa0) /* non-break-space */ wc = 0x20; if (pango_is_zero_width (wc)) { set_glyph (font, glyphs, i, p - text, PANGO_GLYPH_EMPTY); } else { index = find_char (font, wc); if (index) { set_glyph (font, glyphs, i, p - text, index); if (g_unichar_type (wc) == G_UNICODE_NON_SPACING_MARK) { if (i > 0) { PangoRectangle logical_rect, ink_rect; glyphs->glyphs[i].geometry.width = MAX (glyphs->glyphs[i-1].geometry.width, glyphs->glyphs[i].geometry.width); glyphs->glyphs[i-1].geometry.width = 0; glyphs->log_clusters[i] = glyphs->log_clusters[i-1]; /* Some heuristics to try to guess how overstrike glyphs are * done and compensate */ /* FIXME: (alex) Is this double call to get_glyph_extents really necessary? */ pango_font_get_glyph_extents (font, glyphs->glyphs[i].glyph, &ink_rect, &logical_rect); if (logical_rect.width == 0 && ink_rect.x == 0) glyphs->glyphs[i].geometry.x_offset = (glyphs->glyphs[i].geometry.width - ink_rect.width) / 2; } } } else set_glyph (font, glyphs, i, p - text, PANGO_GET_UNKNOWN_GLYPH (wc)); } p = g_utf8_next_char (p); } /* Simple bidi support... may have separate modules later */ if (analysis->level % 2) { int start, end; /* Swap all glyphs */ swap_range (glyphs, 0, n_chars); /* Now reorder glyphs within each cluster back to LTR */ for (start = 0; start < n_chars;) { end = start; while (end < n_chars && glyphs->log_clusters[end] == glyphs->log_clusters[start]) end++; swap_range (glyphs, start, end); start = end; } } }
static void basic_engine_shape (PangoEngineShape *engine, PangoFont *font, const char *text, gint length, const PangoAnalysis *analysis, PangoGlyphString *glyphs) { const char *p; char *copy; CTLineRef line; CFStringRef cstr; CFDictionaryRef attributes; CFAttributedStringRef attstr; PangoCoreTextFont *cfont = PANGO_CORE_TEXT_FONT (font); PangoCoverage *coverage; CFArrayRef runs; CTRunRef run; CTRunStatus run_status; CFIndex i, glyph_count; const CGGlyph *cgglyphs; CFTypeRef keys[] = { (CFTypeRef) kCTFontAttributeName }; CFTypeRef values[] = { pango_core_text_font_get_ctfont (cfont) }; attributes = CFDictionaryCreate (kCFAllocatorDefault, (const void **)keys, (const void **)values, 1, &kCFCopyStringDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); copy = g_strndup (text, length + 1); copy[length] = 0; cstr = CFStringCreateWithCString (kCFAllocatorDefault, copy, kCFStringEncodingUTF8); g_free (copy); attstr = CFAttributedStringCreate (kCFAllocatorDefault, cstr, attributes); line = CTLineCreateWithAttributedString (attstr); runs = CTLineGetGlyphRuns (line); /* Since Pango divides things into runs already, we assume there is * only a single run in this line. */ run = CFArrayGetValueAtIndex (runs, 0); run_status = CTRunGetStatus (run); glyph_count = CTRunGetGlyphCount (run); cgglyphs = CTRunGetGlyphsPtr (run); p = text; pango_glyph_string_set_size (glyphs, glyph_count); coverage = pango_font_get_coverage (PANGO_FONT (cfont), analysis->language); for (i = 0; i < glyph_count; i++) { CFIndex real_i, prev_i; gunichar wc; gunichar mirrored_ch; wc = g_utf8_get_char (p); if (analysis->level % 2) if (pango_get_mirror_char (wc, &mirrored_ch)) wc = mirrored_ch; if (run_status & kCTRunStatusRightToLeft) { real_i = glyph_count - i - 1; prev_i = real_i + 1; } else { real_i = i; prev_i = real_i - 1; } if (wc == 0xa0) /* non-break-space */ wc = 0x20; if (pango_is_zero_width (wc)) { set_glyph (font, glyphs, real_i, p - text, PANGO_GLYPH_EMPTY); } else { PangoCoverageLevel result; result = pango_coverage_get (coverage, wc); if (result != PANGO_COVERAGE_NONE) { set_glyph (font, glyphs, real_i, p - text, cgglyphs[real_i]); if (g_unichar_type (wc) == G_UNICODE_NON_SPACING_MARK) { if (i > 0) { PangoRectangle logical_rect, ink_rect; glyphs->glyphs[real_i].geometry.width = MAX (glyphs->glyphs[prev_i].geometry.width, glyphs->glyphs[prev_i].geometry.width); glyphs->glyphs[prev_i].geometry.width = 0; glyphs->log_clusters[real_i] = glyphs->log_clusters[prev_i]; /* Some heuristics to try to guess how overstrike glyphs are * done and compensate */ pango_font_get_glyph_extents (font, glyphs->glyphs[real_i].glyph, &ink_rect, &logical_rect); if (logical_rect.width == 0 && ink_rect.x == 0) glyphs->glyphs[real_i].geometry.x_offset = (glyphs->glyphs[real_i].geometry.width - ink_rect.width) / 2; } } } else { set_glyph (font, glyphs, real_i, p - text, PANGO_GET_UNKNOWN_GLYPH (wc)); } } p = g_utf8_next_char (p); } CFRelease (line); CFRelease (attstr); CFRelease (cstr); CFRelease (attributes); pango_coverage_unref (coverage); }
JNIEXPORT jobject JNICALL Java_gnu_java_awt_peer_gtk_GdkFontPeer_getGlyphVector (JNIEnv *env, jobject self, jstring chars, jobject font, jobject fontRenderContext) { struct peerfont *pfont = NULL; GList *items = NULL, *i = NULL; gchar *str = NULL; int len, j; double *native_extents; int *native_codes; jintArray java_codes = NULL; jdoubleArray java_extents = NULL; gdk_threads_enter (); pfont = (struct peerfont *)NSA_GET_FONT_PTR (env, self); g_assert (pfont != NULL); len = (*gdk_env())->GetStringUTFLength (env, chars); str = (gchar *)(*env)->GetStringUTFChars (env, chars, NULL); g_assert (str != NULL); if (attrs == NULL) attrs = pango_attr_list_new (); if (len > 0 && str[len-1] == '\0') len--; items = pango_itemize (pfont->ctx, str, 0, len, attrs, NULL); i = g_list_first (items); if (i == NULL) { java_extents = (*env)->NewDoubleArray (env, 0); java_codes = (*env)->NewIntArray (env, 0); } else { PangoGlyphString *glyphs; PangoItem *item = (PangoItem *)i->data; pango_context_set_font_description (pfont->ctx, pfont->desc); pango_context_set_language (pfont->ctx, gtk_get_default_language()); pango_context_load_font (pfont->ctx, pfont->desc); glyphs = pango_glyph_string_new (); g_assert (glyphs != NULL); pango_shape (str + item->offset, item->length, &(item->analysis), glyphs); if (glyphs->num_glyphs > 0) { int x = 0; double scale = ((double) PANGO_SCALE); java_extents = (*env)->NewDoubleArray (env, glyphs->num_glyphs * NUM_GLYPH_METRICS); java_codes = (*env)->NewIntArray (env, glyphs->num_glyphs); native_extents = (*env)->GetDoubleArrayElements (env, java_extents, NULL); native_codes = (*env)->GetIntArrayElements (env, java_codes, NULL); for (j = 0; j < glyphs->num_glyphs; ++j) { PangoRectangle ink; PangoRectangle logical; PangoGlyphGeometry *geom = &glyphs->glyphs[j].geometry; pango_font_get_glyph_extents (pfont->font, glyphs->glyphs[j].glyph, &ink, &logical); native_codes[j] = glyphs->glyphs[j].glyph; native_extents[ GLYPH_LOG_X(j) ] = (logical.x) / scale; native_extents[ GLYPH_LOG_Y(j) ] = (- logical.y) / scale; native_extents[ GLYPH_LOG_WIDTH(j) ] = (logical.width) / scale; native_extents[ GLYPH_LOG_HEIGHT(j) ] = (logical.height) / scale; native_extents[ GLYPH_INK_X(j) ] = (ink.x) / scale; native_extents[ GLYPH_INK_Y(j) ] = (- ink.y) / scale; native_extents[ GLYPH_INK_WIDTH(j) ] = (ink.width) / scale; native_extents[ GLYPH_INK_HEIGHT(j) ] = (ink.height) / scale; native_extents[ GLYPH_POS_X(j) ] = (x + geom->x_offset) / scale; native_extents[ GLYPH_POS_Y(j) ] = ( - geom->y_offset) / scale; x += geom->width; } (*env)->ReleaseDoubleArrayElements (env, java_extents, native_extents, 0); (*env)->ReleaseIntArrayElements (env, java_codes, native_codes, 0); } pango_glyph_string_free (glyphs); } (*env)->ReleaseStringUTFChars (env, chars, str); for (i = g_list_first (items); i != NULL; i = g_list_next (i)) g_free (i->data); g_list_free (items); gdk_threads_leave (); return (*env)->NewObject (env, glyphVector_class, glyphVector_ctor, java_extents, java_codes, font, fontRenderContext); }