void Font::drawComplexText(GraphicsContext* context, const TextRun& run, const FloatPoint& point, int from, int to) const { #if defined(USE_FREETYPE) if (!primaryFont()->platformData().m_pattern) { drawSimpleText(context, run, point, from, to); return; } #endif cairo_t* cr = context->platformContext(); PangoLayout* layout = pango_cairo_create_layout(cr); setPangoAttributes(this, run, layout); gchar* utf8 = convertUniCharToUTF8(run.characters(), run.length(), 0, run.length()); pango_layout_set_text(layout, utf8, -1); // Our layouts are single line PangoLayoutLine* layoutLine = pango_layout_get_line_readonly(layout, 0); // Get the region where this text will be laid out. We will use it to clip // the Cairo context, for when we are only painting part of the text run and // to calculate the size of the shadow buffer. PangoRegionType partialRegion = 0; char* start = g_utf8_offset_to_pointer(utf8, from); char* end = g_utf8_offset_to_pointer(start, to - from); int ranges[] = {start - utf8, end - utf8}; partialRegion = gdk_pango_layout_line_get_clip_region(layoutLine, 0, 0, ranges, 1); drawGlyphsShadow(context, cr, point, layoutLine, partialRegion); cairo_save(cr); cairo_translate(cr, point.x(), point.y()); float red, green, blue, alpha; context->fillColor().getRGBA(red, green, blue, alpha); cairo_set_source_rgba(cr, red, green, blue, alpha); gdk_cairo_region(cr, partialRegion); cairo_clip(cr); pango_cairo_show_layout_line(cr, layoutLine); if (context->textDrawingMode() & TextModeStroke) { Color strokeColor = context->strokeColor(); strokeColor.getRGBA(red, green, blue, alpha); cairo_set_source_rgba(cr, red, green, blue, alpha); pango_cairo_layout_line_path(cr, layoutLine); cairo_set_line_width(cr, context->strokeThickness()); cairo_stroke(cr); } // Pango sometimes leaves behind paths we don't want cairo_new_path(cr); destroyPangoRegion(partialRegion); g_free(utf8); g_object_unref(layout); cairo_restore(cr); }
QFont Font::font() const { QFont f = primaryFont()->getQtFont(); if (m_letterSpacing != 0) f.setLetterSpacing(QFont::AbsoluteSpacing, m_letterSpacing); if (m_wordSpacing != 0) f.setWordSpacing(m_wordSpacing); return f; }
bool Font::primaryFontHasGlyphForCharacter(UChar32 character) const { unsigned pageNumber = (character / GlyphPage::size); GlyphPageTreeNode* node = GlyphPageTreeNode::getRootChild(primaryFont(), pageNumber); GlyphPage* page = node->page(); return page && page->fontDataForCharacter(character); }
float Font::floatWidth(const TextRun& run) const { #if ENABLE(SVG_FONTS) if (primaryFont()->isSVGFont()) return floatWidthUsingSVGFont(run); #endif if (canUseGlyphCache(run)) return floatWidthForSimpleText(run, 0); return floatWidthForComplexText(run); }
float Font::floatWidthForComplexText(const TextRun& run, HashSet<const SimpleFontData*>*) const { SkPaint paint; primaryFont()->platformData().setupPaint(&paint); //printf("--------- complext measure %d chars\n", run.to() - run.from()); SkScalar width = paint.measureText(run.characters(), run.length() << 1); return SkScalarToFloat(width); }
QFont Font::font() const { QFont f = primaryFont()->getQtFont(); f.setWeight(toQFontWeight(weight())); f.setItalic(italic()); if (m_letterSpacing != 0) f.setLetterSpacing(QFont::AbsoluteSpacing, m_letterSpacing); if (m_wordSpacing != 0) f.setWordSpacing(m_wordSpacing); return f; }
int Font::offsetForPosition(const TextRun& run, int x, bool includePartialGlyphs) const { #if ENABLE(SVG_FONTS) if (primaryFont()->isSVGFont()) return offsetForPositionForTextUsingSVGFont(run, x, includePartialGlyphs); #endif if (canUseGlyphCache(run)) return offsetForPositionForSimpleText(run, x, includePartialGlyphs); return offsetForPositionForComplexText(run, x, includePartialGlyphs); }
SVGFontElement* Font::svgFont() const { if (!isSVGFont()) return 0; SVGFontElement* fontElement = 0; SVGFontFaceElement* fontFaceElement = 0; if (svgFontAndFontFaceElementForFontData(primaryFont(), fontFaceElement, fontElement)) return fontElement; return 0; }
FloatRect Font::selectionRectForText(const TextRun& run, const IntPoint& point, int h, int from, int to) const { #if ENABLE(SVG_FONTS) if (primaryFont()->isSVGFont()) return selectionRectForTextUsingSVGFont(run, point, h, from, to); #endif to = (to == -1 ? run.length() : to); if (canUseGlyphCache(run)) return selectionRectForSimpleText(run, point, h, from, to); return selectionRectForComplexText(run, point, h, from, to); }
float Font::floatWidthForComplexText(const TextRun& run, HashSet<const SimpleFontData*>* fallbackFonts, GlyphOverflow*) const { if (run.length() == 0) return run.padding(); const FontPlatformData& fontPlatformData = primaryFont()->platformData(); const float scaleFactor = fontPlatformData.scaleFactor(); Olympia::Platform::Text::Font* font = fontPlatformData.font(); Olympia::Platform::Text::DrawParam drawParam; String sanitized = setupTextDrawing(this, run, &drawParam); // WebKit calls us with plain spaces almost half of the time. // Exit early with a cached value to avoid lots of calls into Text API. if (sanitized.length() == 1 && sanitized[0] == ' ') return primaryFont()->spaceWidth(); #if PLATFORM(EGL) // FIXME: remove after Text API fixes shared context handling if (eglGetCurrentContext() == EGL_NO_CONTEXT) EGLDisplayOpenVG::current()->sharedPlatformSurface()->makeCurrent(); #endif Olympia::Platform::Text::TextMetrics metrics; FontPlatformData::engine()->drawText(0 /* no drawing, only measuring */, *font, sanitized.characters(), sanitized.length(), 0 /*x*/, 0 /*y*/, 0 /* no wrap */, &drawParam, &metrics); if (fallbackFonts && primaryFont()->lineSpacing() < metrics.m_ascent + metrics.m_descent) { FontPlatformData tallerFontPlatformData = fontPlatformData; tallerFontPlatformData.setLineSpacingOverride(metrics.m_ascent, metrics.m_descent); // HACK: We can't generate a cached SimpleFontData from outside of FontCache, // so instead we abuse FontCache::getFontDataForCharacters() to do that. // Safe to use this way because we also pass 0 as string length, // which avoids clashes with possible regular calls of that method. fallbackFonts->add(fontCache()->getFontDataForCharacters(*this, reinterpret_cast<const UChar*>(&tallerFontPlatformData), 0)); } return metrics.m_linearAdvance * scaleFactor; }
float Font::floatWidth(const TextRun& run, int extraCharsAvailable, int& charsConsumed, String& glyphName) const { #if ENABLE(SVG_FONTS) if (primaryFont()->isSVGFont()) return floatWidthUsingSVGFont(run, extraCharsAvailable, charsConsumed, glyphName); #endif charsConsumed = run.length(); glyphName = ""; if (canUseGlyphCache(run)) return floatWidthForSimpleText(run, 0); return floatWidthForComplexText(run); }
void FontFallbackList::determinePitch(const Font* font) const { const FontData* fontData = primaryFont(font); if (!fontData->isSegmented()) m_pitch = static_cast<const SimpleFontData*>(fontData)->pitch(); else { const SegmentedFontData* segmentedFontData = static_cast<const SegmentedFontData*>(fontData); unsigned numRanges = segmentedFontData->numRanges(); if (numRanges == 1) m_pitch = segmentedFontData->rangeAt(0).fontData()->pitch(); else m_pitch = VariablePitch; } }
FloatRect Font::selectionRectForComplexText(const TextRun& run, const IntPoint& point, int h, int from, int to) const { void* font = 0; const UChar* str = 0; const SimpleFontData* sfont = 0; int i, len; float x0,x1,x2; float scale = 0; UChar c = 0; len = run.length(); if (!len) return FloatRect(); if (from>=len || to>len) return FloatRect(); if (from>=to) return FloatRect(); if (from<0) from = 0; if (to>len) to = len; str = run.characters(); sfont = primaryFont(); if (!sfont) return FloatRect(); font = sfont->platformData().Font(); if (!font) return FloatRect(); scale = sfont->platformData().scale(); x0=x1=x2=0; for (i=0; i<from; i++) { c = fixedChar(str[i]); if (!c) continue; x0 += ((float)wkcFontGetCharWidthPeer(font, c) * scale); } for (i=from; i<to; i++) { c = fixedChar(str[i]); if (!c) continue; x1 += ((float)wkcFontGetCharWidthPeer(font, c) * scale); } for (i=to; i<len; i++) { c = fixedChar(str[i]); if (!c) continue; x2 += ((float)wkcFontGetCharWidthPeer(font, c) * scale); } if (run.rtl()) { return FloatRect(point.x() + x2, point.y(), x1, h); } else { return FloatRect(point.x() + x0, point.y(), x1, h); } }
FloatRect Font::selectionRectForComplexText(const TextRun& run, const IntPoint& point, int h, int, int) const { SkPaint paint; SkScalar width, left; SkPaint::FontMetrics metrics; primaryFont()->platformData().setupPaint(&paint); width = paint.measureText(run.characters(), run.length() << 1); SkScalar spacing = paint.getFontMetrics(&metrics); return FloatRect(point.x(), point.y() - floorf(SkScalarToFloat(-metrics.fAscent)), roundf(SkScalarToFloat(width)), roundf(SkScalarToFloat(spacing))); }
void Font::drawComplexText(GraphicsContext* graphicsContext, const TextRunPaintInfo& runInfo, const FloatPoint& point) const { UniscribeHelperTextRun state(runInfo.run, *this); SkColor color = graphicsContext->effectiveFillColor(); unsigned char alpha = SkColorGetA(color); // Skip 100% transparent text; no need to draw anything. if (!alpha && graphicsContext->strokeStyle() == NoStroke) return; HDC hdc = 0; // Uniscribe counts the coordinates from the upper left, while WebKit uses // the baseline, so we have to subtract off the ascent. state.draw(graphicsContext, primaryFont()->platformData(), hdc, lroundf(point.x()), lroundf(point.y() - fontMetrics().ascent()), runInfo.bounds, runInfo.from, runInfo.to); }
float Font::width(const TextRun& run, HashSet<const SimpleFontData*>* fallbackFonts, GlyphOverflow* glyphOverflow) const { #if ENABLE(SVG_FONTS) if (primaryFont()->isSVGFont()) return floatWidthUsingSVGFont(run); #endif CodePath codePathToUse = codePath(run); if (codePathToUse != Complex) { // If the complex text implementation cannot return fallback fonts, avoid // returning them for simple text as well. static bool returnFallbackFonts = canReturnFallbackFontsForComplexText(); return floatWidthForSimpleText(run, 0, returnFallbackFonts ? fallbackFonts : 0, codePathToUse == SimpleWithGlyphOverflow || (glyphOverflow && glyphOverflow->computeBounds) ? glyphOverflow : 0); } return floatWidthForComplexText(run, fallbackFonts, glyphOverflow); }
float Font::width(const TextRun& run, int extraCharsAvailable, int& charsConsumed, String& glyphName) const { #if !ENABLE(SVG_FONTS) UNUSED_PARAM(extraCharsAvailable); #else if (primaryFont()->isSVGFont()) return floatWidthUsingSVGFont(run, extraCharsAvailable, charsConsumed, glyphName); #endif charsConsumed = run.length(); glyphName = ""; if (codePath(run) != Complex) return floatWidthForSimpleText(run, 0); return floatWidthForComplexText(run); }
void Font::drawComplexText(GraphicsContext* gc, TextRun const& run, FloatPoint const& point, int, int) const { SkCanvas* canvas = gc->platformContext()->mCanvas; SkPaint paint; if (!setupForText(&paint, gc, primaryFont())) { return; } // go to chars, instead of glyphs, which was set by setupForText() paint.setTextEncoding(SkPaint::kUTF16_TextEncoding); canvas->drawText(run.characters(), run.length() << 1, SkFloatToScalar(point.x()), SkFloatToScalar(point.y()), paint); }
float Font::floatWidthForComplexText(const TextRun& run, HashSet<const SimpleFontData*>*) const { #if 0 SkPaint paint; primaryFont()->platformData().setupPaint(&paint); //printf("--------- complext measure %d chars\n", run.to() - run.from()); SkScalar width = paint.measureText(run.characters(), run.length() << 1); return SkScalarToFloat(width); #else WidthIterator it(this, run); it.advance(run.length()); return SkScalarToFloat(it.m_runWidthSoFar); #endif }
int Font::offsetForPosition(const TextRun& run, float x, bool includePartialGlyphs) const { #if ENABLE(SVG_FONTS) if (primaryFont()->isSVGFont()) return offsetForPositionForTextUsingSVGFont(run, x, includePartialGlyphs); #endif #if USE(WRATH) //return DrawnTextOfWRATH::offsetForPosition(*this, run, x, includePartialGlyphs); #endif if (codePath(run) != Complex) return offsetForPositionForSimpleText(run, x, includePartialGlyphs); return offsetForPositionForComplexText(run, x, includePartialGlyphs); }
float Font::floatWidthForSimpleText(const TextRun& run, GlyphBuffer* glyphBuffer, HashSet<const SimpleFontData*>* fallbackFonts, GlyphOverflow* glyphOverflow) const { if (!primaryFont()->platformData().size()) return 0; if (!run.length()) return 0; String sanitized = Font::normalizeSpaces(run.characters(), run.length()); QString string = fromRawDataWithoutRef(sanitized); int w = QFontMetrics(font()).width(string, -1, Qt::TextBypassShaping); // WebKit expects us to ignore word spacing on the first character (as opposed to what Qt does) if (treatAsSpace(run[0])) w -= m_wordSpacing; return w + run.expansion(); }
void Font::drawEmphasisMarks(GraphicsContext* context, const TextRun& run, const AtomicString& mark, const FloatPoint& point, int from, int to) const { if (loadingCustomFonts()) return; if (to < 0) to = run.length(); #if ENABLE(SVG_FONTS) // FIXME: Implement for SVG fonts. if (primaryFont()->isSVGFont()) return; #endif if (codePath(run) != Complex) drawEmphasisMarksForSimpleText(context, run, mark, point, from, to); else drawEmphasisMarksForComplexText(context, run, mark, point, from, to); }
FloatRect Font::selectionRectForText(const TextRun& run, const FloatPoint& point, int h, int from, int to) const { #if ENABLE(SVG_FONTS) if (primaryFont()->isSVGFont()) return selectionRectForTextUsingSVGFont(run, point, h, from, to); #endif to = (to == -1 ? run.length() : to); #if USE(WRATH) return DrawnTextOfWRATH::selectionRectForText(*this, run, point, h, from, to); #endif if (codePath(run) != Complex) return selectionRectForSimpleText(run, point, h, from, to); return selectionRectForComplexText(run, point, h, from, to); }
FloatRect Font::selectionRectForComplexText(const TextRun& run, const FloatPoint& point, int h, int from, int to) const { #if USE(FREETYPE) if (!primaryFont()->platformData().m_pattern) return selectionRectForSimpleText(run, point, h, from, to); #endif PangoLayout* layout = getDefaultPangoLayout(run); setPangoAttributes(this, run, layout); gchar* utf8 = convertUniCharToUTF8(run.characters(), run.length(), 0, run.length()); pango_layout_set_text(layout, utf8, -1); char* start = g_utf8_offset_to_pointer(utf8, from); char* end = g_utf8_offset_to_pointer(start, to - from); if (run.ltr()) { from = start - utf8; to = end - utf8; } else { from = end - utf8; to = start - utf8; } PangoLayoutLine* layoutLine = pango_layout_get_line_readonly(layout, 0); int xPos; xPos = 0; if (from < layoutLine->length) pango_layout_line_index_to_x(layoutLine, from, FALSE, &xPos); float beforeWidth = PANGO_PIXELS_FLOOR(xPos); xPos = 0; if (run.ltr() || to < layoutLine->length) pango_layout_line_index_to_x(layoutLine, to, FALSE, &xPos); float afterWidth = PANGO_PIXELS(xPos); g_free(utf8); g_object_unref(layout); return FloatRect(point.x() + beforeWidth, point.y(), afterWidth - beforeWidth, h); }
void Font::drawText(GraphicsContext* context, const TextRun& run, const FloatPoint& point, int from, int to) const { // Don't draw anything while we are using custom fonts that are in the process of loading. if (loadingCustomFonts()) return; to = (to == -1 ? run.length() : to); #if ENABLE(SVG_FONTS) if (primaryFont()->isSVGFont()) { drawTextUsingSVGFont(context, run, point, from, to); return; } #endif if (codePath(run) != Complex) return drawSimpleText(context, run, point, from, to); return drawComplexText(context, run, point, from, to); }
float Font::floatWidthForComplexText(const TextRun& run, HashSet<const SimpleFontData*>*, GlyphOverflow*) const { if (!primaryFont()->platformData().size()) return 0; if (!run.length()) return 0; if (run.length() == 1 && treatAsSpace(run[0])) return QFontMetrics(font()).width(space) + run.padding(); String sanitized = Font::normalizeSpaces(String(run.characters(), run.length())); QString string = fromRawDataWithoutRef(sanitized); int w = QFontMetrics(font()).width(string); // WebKit expects us to ignore word spacing on the first character (as opposed to what Qt does) if (treatAsSpace(run[0])) w -= m_wordSpacing; return w + run.padding(); }
int Font::offsetForPositionForComplexText(const TextRun& run, float position, bool includePartialGlyphs) const { // In here, we determine the cursor index for an x (mouse-click) position. const FontPlatformData& fontPlatformData = primaryFont()->platformData(); const float scaleFactor = fontPlatformData.scaleFactor(); Olympia::Platform::Text::Font* font = fontPlatformData.font(); Olympia::Platform::Text::DrawParam drawParam; String sanitized = setupTextDrawing(this, run, &drawParam); #if PLATFORM(EGL) // FIXME: remove after Text API fixes shared context handling if (eglGetCurrentContext() == EGL_NO_CONTEXT) EGLDisplayOpenVG::current()->sharedPlatformSurface()->makeCurrent(); #endif int offset; FontPlatformData::engine()->xToTextPos(position / scaleFactor, offset, Olympia::Platform::Text::TextPosRoundNearest, *font, sanitized.characters(), sanitized.length(), drawParam); return offset; }
FloatRect Font::selectionRectForComplexText(const TextRun& run, const FloatPoint& point, int height, int from, int to, int width) const { const FontPlatformData& fontPlatformData = primaryFont()->platformData(); const float scaleFactor = fontPlatformData.scaleFactor(); Olympia::Platform::Text::Font* font = fontPlatformData.font(); Olympia::Platform::Text::DrawParam drawParam; String sanitized = setupTextDrawing(this, run, &drawParam); adjustOffsetsForTextDrawing(run, from, to); #if PLATFORM(EGL) // FIXME: remove after Text API fixes shared context handling if (eglGetCurrentContext() == EGL_NO_CONTEXT) EGLDisplayOpenVG::current()->sharedPlatformSurface()->makeCurrent(); #endif double fromX; FontPlatformData::engine()->textPosToX(from, fromX, *font, sanitized.characters(), sanitized.length(), drawParam); ASSERT_VG_NO_ERROR(); fromX *= scaleFactor; double toX; FontPlatformData::engine()->textPosToX(to, toX, *font, sanitized.characters(), sanitized.length(), drawParam); ASSERT_VG_NO_ERROR(); toX *= scaleFactor; if (width) { double bound = width * scaleFactor; if (from == run.length()) fromX = bound; if (to == run.length()) toX = bound; } return (toX > fromX) ? FloatRect(point.x() + fromX, point.y(), toX - fromX, height) : FloatRect(point.x() + toX, point.y(), fromX - toX, height); }
float Font::floatWidthForComplexText(const TextRun& run, HashSet<const SimpleFontData*>* fallbackFonts, GlyphOverflow* overflow) const { #if USE(FREETYPE) if (!primaryFont()->platformData().m_pattern) return floatWidthForSimpleText(run, 0, fallbackFonts, overflow); #endif if (!run.length()) return 0.0f; PangoLayout* layout = getDefaultPangoLayout(run); setPangoAttributes(this, run, layout); gchar* utf8 = convertUniCharToUTF8(run.characters(), run.length(), 0, run.length()); pango_layout_set_text(layout, utf8, -1); int width; pango_layout_get_pixel_size(layout, &width, 0); g_free(utf8); g_object_unref(layout); return width; }
int Font::offsetForPositionForComplexText(const TextRun& run, int x, bool includePartialGlyphs) const { SkPaint paint; int count = run.length(); SkAutoSTMalloc<64, SkScalar> storage(count); SkScalar* widths = storage.get(); primaryFont()->platformData().setupPaint(&paint); count = paint.getTextWidths(run.characters(), count << 1, widths); if (count > 0) { SkScalar pos = 0; for (int i = 0; i < count; i++) { if (x < SkScalarRound(pos + SkScalarHalf(widths[i]))) return i; pos += widths[i]; } } return count; }