bool GlyphPage::fill(unsigned offset, unsigned length, UChar* buffer, unsigned bufferLength, const SimpleFontData* fontData) { // The bufferLength will be greater than the glyph page size if the buffer has Unicode supplementary characters. // We won't support this for now. if (bufferLength > GlyphPage::size) return false; cairo_scaled_font_t* scaledFont = fontData->platformData().scaledFont(); if (!scaledFont) return false; FT_Face face = cairo_ft_scaled_font_lock_face(scaledFont); if (!face) return false; bool haveGlyphs = false; for (unsigned i = 0; i < length; i++) { Glyph glyph = FcFreeTypeCharIndex(face, buffer[i]); if (!glyph) setGlyphDataForIndex(offset + i, 0, 0); else { setGlyphDataForIndex(offset + i, glyph, fontData); haveGlyphs = true; } } cairo_ft_scaled_font_unlock_face(scaledFont); return haveGlyphs; }
bool SimpleFontData::canRenderCombiningCharacterSequence(const UChar* characters, size_t length) const { if (!m_combiningCharacterSequenceSupport) m_combiningCharacterSequenceSupport = adoptPtr(new HashMap<String, bool>); WTF::HashMap<String, bool>::AddResult addResult = m_combiningCharacterSequenceSupport->add(String(characters, length), false); if (!addResult.isNewEntry) return addResult.iterator->value; UErrorCode error = U_ZERO_ERROR; Vector<UChar, 4> normalizedCharacters(length); int32_t normalizedLength = unorm_normalize(characters, length, UNORM_NFC, UNORM_UNICODE_3_2, &normalizedCharacters[0], length, &error); // Can't render if we have an error or no composition occurred. if (U_FAILURE(error) || (static_cast<size_t>(normalizedLength) == length)) return false; FT_Face face = cairo_ft_scaled_font_lock_face(m_platformData.scaledFont()); if (!face) return false; if (FcFreeTypeCharIndex(face, normalizedCharacters[0])) addResult.iterator->value = true; cairo_ft_scaled_font_unlock_face(m_platformData.scaledFont()); return addResult.iterator->value; }
PassRefPtr<SharedBuffer> FontPlatformData::openTypeTable(uint32_t table) const { FT_Face freeTypeFace = cairo_ft_scaled_font_lock_face(m_scaledFont); if (!freeTypeFace) return 0; FT_ULong tableSize = 0; // Tag bytes need to be reversed because OT_MAKE_TAG uses big-endian order. uint32_t tag = FT_MAKE_TAG((table & 0xff), (table & 0xff00) >> 8, (table & 0xff0000) >> 16, table >> 24); if (FT_Load_Sfnt_Table(freeTypeFace, tag, 0, 0, &tableSize)) return 0; RefPtr<SharedBuffer> buffer = SharedBuffer::create(tableSize); FT_ULong expectedTableSize = tableSize; if (buffer->size() != tableSize) return 0; FT_Error error = FT_Load_Sfnt_Table(freeTypeFace, tag, 0, reinterpret_cast<FT_Byte*>(const_cast<char*>(buffer->data())), &tableSize); if (error || tableSize != expectedTableSize) return 0; cairo_ft_scaled_font_unlock_face(m_scaledFont); return buffer.release(); }
bool GlyphPage::fill(unsigned offset, unsigned length, UChar* buffer, unsigned bufferLength, const Font* fontData) { cairo_scaled_font_t* scaledFont = fontData->platformData().scaledFont(); ASSERT(scaledFont); FT_Face face = cairo_ft_scaled_font_lock_face(scaledFont); if (!face) return false; bool haveGlyphs = false; UTF16UChar32Iterator iterator(buffer, bufferLength); for (unsigned i = 0; i < length; i++) { UChar32 character = iterator.next(); if (character == iterator.end()) break; Glyph glyph = FcFreeTypeCharIndex(face, character); if (!glyph) setGlyphDataForIndex(offset + i, 0, 0); else { setGlyphDataForIndex(offset + i, glyph, fontData); haveGlyphs = true; } } cairo_ft_scaled_font_unlock_face(scaledFont); return haveGlyphs; }
static cairo_status_t glyph_array_add_text(glyph_array_t *glyphs, cairo_t *cr, const char *s, double spacing) { cairo_scaled_font_t *scaled_font; cairo_status_t status; FT_Face face; unsigned long charcode; unsigned int index; cairo_text_extents_t extents; const char *p; FT_Vector kerning; double kern_x; int first = TRUE; scaled_font = cairo_get_scaled_font (cr); status = cairo_scaled_font_status (scaled_font); if (status) return status; face = cairo_ft_scaled_font_lock_face (scaled_font); if (face == NULL) return CAIRO_STATUS_FONT_TYPE_MISMATCH; p = s; while (*p) { charcode = *p; index = FT_Get_Char_Index (face, charcode); glyphs->glyph_list[glyphs->num_glyphs].index = index; if (first) { first = FALSE; glyphs->glyph_list[glyphs->num_glyphs].x = glyphs->x; glyphs->glyph_list[glyphs->num_glyphs].y = glyphs->y; } else { cairo_glyph_extents (cr, &glyphs->glyph_list[glyphs->num_glyphs - 1], 1, &extents); FT_Get_Kerning (face, glyphs->glyph_list[glyphs->num_glyphs - 1].index, glyphs->glyph_list[glyphs->num_glyphs].index, FT_KERNING_UNSCALED, &kerning); kern_x = DOUBLE_FROM_26_6(kerning.x); glyphs->glyph_list[glyphs->num_glyphs].x = glyphs->glyph_list[glyphs->num_glyphs - 1].x + extents.x_advance + kern_x + spacing; glyphs->glyph_list[glyphs->num_glyphs].y = glyphs->glyph_list[glyphs->num_glyphs - 1].y + extents.y_advance; } cairo_glyph_extents (cr, &glyphs->glyph_list[glyphs->num_glyphs], 1, &extents); glyphs->x = glyphs->glyph_list[glyphs->num_glyphs].x + extents.x_advance + spacing; glyphs->y = glyphs->glyph_list[glyphs->num_glyphs].y + extents.y_advance; p++; glyphs->num_glyphs++; } cairo_ft_scaled_font_unlock_face (scaled_font); return CAIRO_STATUS_SUCCESS; }
bool FontPlatformData::hasCompatibleCharmap() { ASSERT(m_scaledFont); FT_Face freeTypeFace = cairo_ft_scaled_font_lock_face(m_scaledFont); bool hasCompatibleCharmap = !(FT_Select_Charmap(freeTypeFace, ft_encoding_unicode) && FT_Select_Charmap(freeTypeFace, ft_encoding_symbol) && FT_Select_Charmap(freeTypeFace, ft_encoding_apple_roman)); cairo_ft_scaled_font_unlock_face(m_scaledFont); return hasCompatibleCharmap; }
static FT_Face pango_cairo_fc_font_lock_face (PangoFcFont *font) { PangoCairoFcFont *cffont = (PangoCairoFcFont *) (font); cairo_scaled_font_t *scaled_font = _pango_cairo_font_private_get_scaled_font (&cffont->cf_priv); if (G_UNLIKELY (!scaled_font)) return NULL; return cairo_ft_scaled_font_lock_face (scaled_font); }
// gfxOS2Font::GetMetrics() // return the metrics of the current font using the gfxFont metrics structure. // If the metrics are not available yet, compute them using the FreeType // function on the font. (This is partly based on the respective function from // gfxPangoFonts) const gfxFont::Metrics& gfxOS2Font::GetMetrics() { #ifdef DEBUG_thebes_1 printf("gfxOS2Font[%#x]::GetMetrics()\n", (unsigned)this); #endif if (mMetrics) { return *mMetrics; } // whatever happens below, we can always create the metrics mMetrics = new gfxFont::Metrics; mSpaceGlyph = 0; // round size to integer pixels, this is to get full pixels for layout // together with internal/external leading (see below) mMetrics->emHeight = NS_floor(GetStyle()->size + 0.5); FT_Face face = cairo_ft_scaled_font_lock_face(CairoScaledFont()); if (!face) { // Abort here already, otherwise we crash in the following // this can happen if the font-size requested is zero. FillMetricsDefaults(mMetrics); return *mMetrics; } if (!face->charmap) { // Also abort, if the charmap isn't loaded; then the char // lookups won't work. This happens for fonts without Unicode // charmap. cairo_ft_scaled_font_unlock_face(CairoScaledFont()); FillMetricsDefaults(mMetrics); return *mMetrics; } // compute font scaling factors gfxFloat emUnit = 1.0 * face->units_per_EM; gfxFloat xScale = face->size->metrics.x_ppem / emUnit; gfxFloat yScale = face->size->metrics.y_ppem / emUnit; FT_UInt gid; // glyph ID // properties of space gid = FT_Get_Char_Index(face, ' '); if (gid) { // Load glyph into glyph slot. Use load_default here to get results in // 26.6 fractional pixel format which is what is used for all other // characters in gfxOS2FontGroup::CreateGlyphRunsFT. FT_Load_Glyph(face, gid, FT_LOAD_DEFAULT); // glyph width doesn't work for spaces, use advance instead mMetrics->spaceWidth = face->glyph->advance.x >> 6; // save the space glyph mSpaceGlyph = gid; } else {
FontPlatformData::FontPlatformData(cairo_font_face_t* fontFace, float size, bool bold, bool italic) : m_fallbacks(0) , m_size(size) , m_syntheticBold(bold) , m_syntheticOblique(italic) { initializeWithFontFace(fontFace); FT_Face fontConfigFace = cairo_ft_scaled_font_lock_face(m_scaledFont.get()); if (fontConfigFace) { m_fixedWidth = fontConfigFace->face_flags & FT_FACE_FLAG_FIXED_WIDTH; cairo_ft_scaled_font_unlock_face(m_scaledFont.get()); } }
already_AddRefed<gfxOS2Font> gfxOS2Platform::FindFontForChar(PRUint32 aCh, gfxOS2Font *aFont) { #ifdef DEBUG_thebes printf("gfxOS2Platform::FindFontForChar(%d, ...)\n", aCh); #endif // is codepoint with no matching font? return null immediately if (mCodepointsWithNoFonts.test(aCh)) { return nsnull; } // the following is not very clever but it's a quick fix to search all fonts // (one should instead cache the charmaps as done on Mac and Win) // just continue to append all fonts known to the system nsTArray<nsString> fontList; nsCAutoString generic; nsresult rv = GetFontList(aFont->GetStyle()->langGroup, generic, fontList); if (NS_SUCCEEDED(rv)) { // start at 3 to skip over the generic entries for (PRUint32 i = 3; i < fontList.Length(); i++) { #ifdef DEBUG_thebes printf("searching in entry i=%d (%s)\n", i, NS_LossyConvertUTF16toASCII(fontList[i]).get()); #endif nsRefPtr<gfxOS2Font> font = gfxOS2Font::GetOrMakeFont(fontList[i], aFont->GetStyle()); if (!font) continue; FT_Face face = cairo_ft_scaled_font_lock_face(font->CairoScaledFont()); if (!face || !face->charmap) { if (face) cairo_ft_scaled_font_unlock_face(font->CairoScaledFont()); continue; } FT_UInt gid = FT_Get_Char_Index(face, aCh); // find the glyph id if (gid != 0) { // this is the font cairo_ft_scaled_font_unlock_face(font->CairoScaledFont()); return font.forget(); } } } // no match found, so add to the set of non-matching codepoints mCodepointsWithNoFonts.set(aCh); return nsnull; }
static cairo_test_status_t draw (cairo_t *cr, int width, int height) { cairo_font_options_t *font_options; cairo_scaled_font_t *scaled_font; FT_Face face; FT_ULong charcode; FT_UInt idx; int i = 0; cairo_glyph_t glyphs[NUM_GLYPHS]; /* paint white so we don't need separate ref images for * RGB24 and ARGB32 */ cairo_set_source_rgb (cr, 1.0, 1.0, 1.0); cairo_paint (cr); cairo_select_font_face (cr, "Bitstream Vera Sans", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_NORMAL); cairo_set_font_size (cr, TEXT_SIZE); font_options = cairo_font_options_create (); cairo_get_font_options (cr, font_options); cairo_font_options_set_hint_metrics (font_options, CAIRO_HINT_METRICS_OFF); cairo_set_font_options (cr, font_options); cairo_font_options_destroy (font_options); cairo_set_source_rgb (cr, 0.0, 0.0, 0.0); scaled_font = cairo_get_scaled_font (cr); face = cairo_ft_scaled_font_lock_face (scaled_font); { charcode = FT_Get_First_Char(face, &idx); while (idx && (i < NUM_GLYPHS)) { glyphs[i] = (cairo_glyph_t) {idx, PAD + GRID_SIZE * (i/GRID_ROWS), PAD + TEXT_SIZE + GRID_SIZE * (i%GRID_ROWS)}; i++; charcode = FT_Get_Next_Char(face, charcode, &idx); } } cairo_ft_scaled_font_unlock_face (scaled_font); cairo_show_glyphs(cr, glyphs, i); return CAIRO_TEST_SUCCESS; }
bool SimpleFontData::containsCharacters(const UChar* characters, int length) const { FT_Face face = cairo_ft_scaled_font_lock_face(m_platformData.m_scaledFont); if (!face) return false; for (int i = 0; i < length; i++) { if (FcFreeTypeCharIndex(face, characters[i]) == 0) { cairo_ft_scaled_font_unlock_face(m_platformData.m_scaledFont); return false; } } cairo_ft_scaled_font_unlock_face(m_platformData.m_scaledFont); return true; }
static cairo_int_status_t _cairo_qt_surface_show_glyphs (void *abstract_surface, cairo_operator_t op, const cairo_pattern_t *source, cairo_glyph_t *glyphs, int num_glyphs, cairo_scaled_font_t *scaled_font, const cairo_clip_t *clip) { #if (QT_VERSION >= QT_VERSION_CHECK(4, 7, 0)) || defined(QT_GLYPHS_API_BACKPORT) cairo_qt_surface_t *qs = (cairo_qt_surface_t *) abstract_surface; // pick out the colour to use from the cairo source cairo_solid_pattern_t *solid = (cairo_solid_pattern_t*) source; cairo_scaled_glyph_t* glyph; // documentation says you have to freeze the cache, but I don't believe it _cairo_scaled_font_freeze_cache(scaled_font); QColor tempColour(solid->color.red * 255, solid->color.green * 255, solid->color.blue * 255); QVarLengthArray<QPointF> positions(num_glyphs); QVarLengthArray<unsigned int> glyphss(num_glyphs); FT_Face face = cairo_ft_scaled_font_lock_face (scaled_font); const FT_Size_Metrics& ftMetrics = face->size->metrics; QFont font(face->family_name); font.setStyleStrategy(QFont::NoFontMerging); font.setBold(face->style_flags & FT_STYLE_FLAG_BOLD); font.setItalic(face->style_flags & FT_STYLE_FLAG_ITALIC); font.setKerning(face->face_flags & FT_FACE_FLAG_KERNING); font.setPixelSize(ftMetrics.y_ppem); cairo_ft_scaled_font_unlock_face(scaled_font); qs->p->setFont(font); qs->p->setPen(tempColour); for (int currentGlyph = 0; currentGlyph < num_glyphs; currentGlyph++) { positions[currentGlyph].setX(glyphs[currentGlyph].x); positions[currentGlyph].setY(glyphs[currentGlyph].y); glyphss[currentGlyph] = glyphs[currentGlyph].index; } qt_draw_glyphs(qs->p, glyphss.data(), positions.data(), num_glyphs); _cairo_scaled_font_thaw_cache(scaled_font); return CAIRO_INT_STATUS_SUCCESS; #else return CAIRO_INT_STATUS_UNSUPPORTED; #endif }
bool SimpleFontData::containsCharacters(const UChar* characters, int bufferLength) const { ASSERT(m_platformData.scaledFont()); FT_Face face = cairo_ft_scaled_font_lock_face(m_platformData.scaledFont()); if (!face) return false; UTF16UChar32Iterator iterator(characters, bufferLength); UChar32 character = iterator.next(); while (character != iterator.end()) { if (!FcFreeTypeCharIndex(face, character)) { cairo_ft_scaled_font_unlock_face(m_platformData.scaledFont()); return false; } character = iterator.next(); } cairo_ft_scaled_font_unlock_face(m_platformData.scaledFont()); return true; }
bool SimpleFontData::containsCharacters(const UChar* characters, int length) const { // If this is a no-op font (zero size), then it should always contain the characters, // since we never read from or render from this font. if (!m_platformData.scaledFont()) return true; FT_Face face = cairo_ft_scaled_font_lock_face(m_platformData.scaledFont()); if (!face) return false; for (int i = 0; i < length; i++) { if (FcFreeTypeCharIndex(face, characters[i]) == 0) { cairo_ft_scaled_font_unlock_face(m_platformData.scaledFont()); return false; } } cairo_ft_scaled_font_unlock_face(m_platformData.scaledFont()); return true; }
void SimpleFontData::platformInit() { if (!m_platformData.m_size) return; ASSERT(m_platformData.scaledFont()); cairo_font_extents_t fontExtents; cairo_scaled_font_extents(m_platformData.scaledFont(), &fontExtents); float ascent = narrowPrecisionToFloat(fontExtents.ascent); float descent = narrowPrecisionToFloat(fontExtents.descent); float lineGap = narrowPrecisionToFloat(fontExtents.height - fontExtents.ascent - fontExtents.descent); m_fontMetrics.setAscent(ascent); m_fontMetrics.setDescent(descent); #if PLATFORM(EFL) m_fontMetrics.setLineSpacing(ascent + descent + lineGap); #else // Match CoreGraphics metrics. m_fontMetrics.setLineSpacing(lroundf(ascent) + lroundf(descent) + lroundf(lineGap)); #endif m_fontMetrics.setLineGap(lineGap); cairo_text_extents_t textExtents; cairo_scaled_font_text_extents(m_platformData.scaledFont(), "x", &textExtents); m_fontMetrics.setXHeight(narrowPrecisionToFloat((platformData().orientation() == Horizontal) ? textExtents.height : textExtents.width)); cairo_scaled_font_text_extents(m_platformData.scaledFont(), " ", &textExtents); m_spaceWidth = narrowPrecisionToFloat((platformData().orientation() == Horizontal) ? textExtents.x_advance : -textExtents.y_advance); if ((platformData().orientation() == Vertical) && !isTextOrientationFallback()) { FT_Face freeTypeFace = cairo_ft_scaled_font_lock_face(m_platformData.scaledFont()); m_fontMetrics.setUnitsPerEm(freeTypeFace->units_per_EM); cairo_ft_scaled_font_unlock_face(m_platformData.scaledFont()); } m_syntheticBoldOffset = m_platformData.syntheticBold() ? 1.0f : 0.f; }
CairoLockedFTFace(cairo_scaled_font_t* scaledFont) : fScaledFont(scaledFont) , fFace(cairo_ft_scaled_font_lock_face(scaledFont)) {}
static void text_to_glyphs (cairo_t *cr, const gchar *text, cairo_glyph_t **glyphs, int *num_glyphs) { PangoAttribute *fallback_attr; PangoAttrList *attr_list; PangoContext *context; PangoDirection base_dir; GList *items; GList *visual_items; FT_Face ft_face; hb_font_t *hb_font; gdouble x = 0, y = 0; gint i; gdouble x_scale, y_scale; *num_glyphs = 0; *glyphs = NULL; base_dir = pango_find_base_dir (text, -1); cairo_scaled_font_t *cr_font = cairo_get_scaled_font (cr); ft_face = cairo_ft_scaled_font_lock_face (cr_font); hb_font = hb_ft_font_create (ft_face, NULL); cairo_surface_t *target = cairo_get_target (cr); cairo_surface_get_device_scale (target, &x_scale, &y_scale); /* We abuse pango itemazation to split text into script and direction * runs, since we use our fonts directly no through pango, we don't * bother changing the default font, but we disable font fallback as * pango will split runs at font change */ context = pango_cairo_create_context (cr); attr_list = pango_attr_list_new (); fallback_attr = pango_attr_fallback_new (FALSE); pango_attr_list_insert (attr_list, fallback_attr); items = pango_itemize_with_base_dir (context, base_dir, text, 0, strlen (text), attr_list, NULL); g_object_unref (context); pango_attr_list_unref (attr_list); /* reorder the items in the visual order */ visual_items = pango_reorder_items (items); while (visual_items) { PangoItem *item; PangoAnalysis analysis; hb_buffer_t *hb_buffer; hb_glyph_info_t *hb_glyphs; hb_glyph_position_t *hb_positions; gint n; item = visual_items->data; analysis = item->analysis; hb_buffer = hb_buffer_create (); hb_buffer_add_utf8 (hb_buffer, text, -1, item->offset, item->length); hb_buffer_set_script (hb_buffer, hb_glib_script_to_script (analysis.script)); hb_buffer_set_language (hb_buffer, hb_language_from_string (pango_language_to_string (analysis.language), -1)); hb_buffer_set_direction (hb_buffer, analysis.level % 2 ? HB_DIRECTION_RTL : HB_DIRECTION_LTR); hb_shape (hb_font, hb_buffer, NULL, 0); n = hb_buffer_get_length (hb_buffer); hb_glyphs = hb_buffer_get_glyph_infos (hb_buffer, NULL); hb_positions = hb_buffer_get_glyph_positions (hb_buffer, NULL); *glyphs = g_renew (cairo_glyph_t, *glyphs, *num_glyphs + n); for (i = 0; i < n; i++) { (*glyphs)[*num_glyphs + i].index = hb_glyphs[i].codepoint; (*glyphs)[*num_glyphs + i].x = x + (hb_positions[i].x_offset / (64. * x_scale)); (*glyphs)[*num_glyphs + i].y = y - (hb_positions[i].y_offset / (64. * y_scale)); x += (hb_positions[i].x_advance / (64. * x_scale)); y -= (hb_positions[i].y_advance / (64. * y_scale)); } *num_glyphs += n; hb_buffer_destroy (hb_buffer); visual_items = visual_items->next; } g_list_free_full (visual_items, (GDestroyNotify) pango_item_free); g_list_free_full (items, (GDestroyNotify) pango_item_free); hb_font_destroy (hb_font); cairo_ft_scaled_font_unlock_face (cr_font); }