Example #1
0
float Font::width(const TextRun& run, HashSet<const SimpleFontData*>* fallbackFonts, GlyphOverflow* glyphOverflow) const
{
    CodePath codePathToUse = codePath(run);
    if (codePathToUse != ComplexPath) {
        // The complex path is more restrictive about returning fallback fonts than the simple path, so we need an explicit test to make their behaviors match.
        if (!FontPlatformFeatures::canReturnFallbackFontsForComplexText())
            fallbackFonts = 0;
        // The simple path can optimize the case where glyph overflow is not observable.
        if (codePathToUse != SimpleWithGlyphOverflowPath && (glyphOverflow && !glyphOverflow->computeBounds))
            glyphOverflow = 0;
    }

    bool hasKerningOrLigatures = fontDescription().typesettingFeatures() & (Kerning | Ligatures);
    bool hasWordSpacingOrLetterSpacing = fontDescription().wordSpacing() || fontDescription().letterSpacing();
    float* cacheEntry = m_fontFallbackList->widthCache().add(run, std::numeric_limits<float>::quiet_NaN(), hasKerningOrLigatures, hasWordSpacingOrLetterSpacing, glyphOverflow);
    if (cacheEntry && !std::isnan(*cacheEntry))
        return *cacheEntry;

    float result;
    if (codePathToUse == ComplexPath)
        result = floatWidthForComplexText(run, fallbackFonts, glyphOverflow);
    else
        result = floatWidthForSimpleText(run, fallbackFonts, glyphOverflow);

    if (cacheEntry && (!fallbackFonts || fallbackFonts->isEmpty()))
        *cacheEntry = result;
    return result;
}
Example #2
0
void RenderSVGInlineText::computeNewScaledFontForStyle(RenderObject* renderer, const RenderStyle* style, float& scalingFactor, Font& scaledFont)
{
    ASSERT(style);
    ASSERT(renderer);

    Document* document = renderer->document();
    ASSERT(document);
    
    StyleResolver* styleResolver = document->styleResolver();
    ASSERT(styleResolver);

    // Alter font-size to the right on-screen value to avoid scaling the glyphs themselves, except when GeometricPrecision is specified
    scalingFactor = SVGRenderingContext::calculateScreenFontSizeScalingFactor(renderer);
    if (scalingFactor == 1 || !scalingFactor || style->fontDescription().textRenderingMode() == GeometricPrecision) {
        scalingFactor = 1;
        scaledFont = style->font();
        return;
    }

    FontDescription fontDescription(style->fontDescription());

    // FIXME: We need to better handle the case when we compute very small fonts below (below 1pt).
    fontDescription.setComputedSize(StyleResolver::getComputedSizeFromSpecifiedSize(document, scalingFactor, fontDescription.isAbsoluteSize(), fontDescription.computedSize(), DoNotUseSmartMinimumForFontSize));

    scaledFont = Font(fontDescription, 0, 0);
    scaledFont.update(styleResolver->fontSelector());
}
void LayoutSVGInlineText::computeNewScaledFontForStyle(LayoutObject* layoutObject, const ComputedStyle* style, float& scalingFactor, Font& scaledFont)
{
    ASSERT(style);
    ASSERT(layoutObject);

    // Alter font-size to the right on-screen value to avoid scaling the glyphs themselves, except when GeometricPrecision is specified.
    scalingFactor = SVGLayoutSupport::calculateScreenFontSizeScalingFactor(layoutObject);
    if (style->effectiveZoom() == 1 && (scalingFactor == 1 || !scalingFactor)) {
        scalingFactor = 1;
        scaledFont = style->font();
        return;
    }

    if (style->fontDescription().textRendering() == GeometricPrecision)
        scalingFactor = 1;

    FontDescription fontDescription(style->fontDescription());

    Document& document = layoutObject->document();
    // FIXME: We need to better handle the case when we compute very small fonts below (below 1pt).
    fontDescription.setComputedSize(FontSize::getComputedSizeFromSpecifiedSize(&document, scalingFactor, fontDescription.isAbsoluteSize(), fontDescription.specifiedSize(), DoNotUseSmartMinimumForFontSize));

    scaledFont = Font(fontDescription);
    scaledFont.update(document.styleEngine().fontSelector());
}
Example #4
0
int Font::offsetForPosition(const TextRun& run, float x, bool includePartialGlyphs) const
{
    // FIXME: Use the fast code path once it handles partial runs with kerning and ligatures. See http://webkit.org/b/100050
    if (codePath(run) != ComplexPath && !fontDescription().typesettingFeatures())
        return offsetForPositionForSimpleText(run, x, includePartialGlyphs);

    return offsetForPositionForComplexText(run, x, includePartialGlyphs);
}
Example #5
0
void floatWidthMissingGlyphCallback(const TextRun& run, SVGTextRunWalkerMeasuredLengthData& data)
{
    // Handle system font fallback
    FontDescription fontDescription(data.font->fontDescription());
    fontDescription.setFamily(FontFamily());
    Font font(fontDescription, 0, 0); // spacing handled by SVG text code.
    font.update(data.font->fontSelector());

    data.length += font.floatWidth(run);
}
Example #6
0
Font::Font(const FontPlatformData& fontData, bool isPrinterFont, FontSmoothingMode fontSmoothingMode)
    : m_fontList(FontFallbackList::create())
    , m_letterSpacing(0)
    , m_wordSpacing(0)
    , m_isPlatformFont(true)
{
    m_fontDescription.setUsePrinterFont(isPrinterFont);
    m_fontDescription.setFontSmoothing(fontSmoothingMode);
    m_needsTranscoding = fontTranscoder().needsTranscoding(fontDescription());
    m_fontList->setPlatformFont(fontData);
}
Example #7
0
FloatRect Font::selectionRectForText(const TextRun& run, const FloatPoint& point, int h, int from, int to) const
{
    to = (to == -1 ? run.length() : to);

    CodePath codePathToUse = codePath(run);
    // FIXME: Use the fast code path once it handles partial runs with kerning and ligatures. See http://webkit.org/b/100050
    if (codePathToUse != ComplexPath && fontDescription().typesettingFeatures() && (from || to != run.length()))
        codePathToUse = ComplexPath;

    if (codePathToUse != ComplexPath)
        return selectionRectForSimpleText(run, point, h, from, to);

    return selectionRectForComplexText(run, point, h, from, to);
}
Example #8
0
void Font::drawEmphasisMarks(GraphicsContext* context, const TextRunPaintInfo& runInfo, const AtomicString& mark, const FloatPoint& point) const
{
    if (loadingCustomFonts())
        return;

    CodePath codePathToUse = codePath(runInfo.run);
    // FIXME: Use the fast code path once it handles partial runs with kerning and ligatures. See http://webkit.org/b/100050
    if (codePathToUse != ComplexPath && fontDescription().typesettingFeatures() && (runInfo.from || runInfo.to != runInfo.run.length()))
        codePathToUse = ComplexPath;

    if (codePathToUse != ComplexPath)
        drawEmphasisMarksForSimpleText(context, runInfo, mark, point);
    else
        drawEmphasisMarksForComplexText(context, runInfo, mark, point);
}
Example #9
0
float Font::floatWidthForSimpleText(const TextRun& run, HashSet<const SimpleFontData*>* fallbackFonts, GlyphOverflow* glyphOverflow) const
{
    WidthIterator it(this, run, fallbackFonts, glyphOverflow);
    GlyphBuffer glyphBuffer;
    it.advance(run.length(), (fontDescription().typesettingFeatures() & (Kerning | Ligatures)) ? &glyphBuffer : 0);

    if (glyphOverflow) {
        glyphOverflow->top = max<int>(glyphOverflow->top, ceilf(-it.minGlyphBoundingBoxY()) - (glyphOverflow->computeBounds ? 0 : fontMetrics().ascent()));
        glyphOverflow->bottom = max<int>(glyphOverflow->bottom, ceilf(it.maxGlyphBoundingBoxY()) - (glyphOverflow->computeBounds ? 0 : fontMetrics().descent()));
        glyphOverflow->left = ceilf(it.firstGlyphOverflow());
        glyphOverflow->right = ceilf(it.lastGlyphOverflow());
    }

    return it.m_runWidthSoFar;
}
Example #10
0
void Font::drawText(GraphicsContext* context, const TextRunPaintInfo& runInfo, const FloatPoint& point, CustomFontNotReadyAction customFontNotReadyAction) const
{
    // Don't draw anything while we are using custom fonts that are in the process of loading,
    // except if the 'force' argument is set to true (in which case it will use a fallback
    // font).
    if (loadingCustomFonts() && customFontNotReadyAction == DoNotPaintIfFontNotReady)
        return;

    CodePath codePathToUse = codePath(runInfo.run);
    // FIXME: Use the fast code path once it handles partial runs with kerning and ligatures. See http://webkit.org/b/100050
    if (codePathToUse != ComplexPath && fontDescription().typesettingFeatures() && (runInfo.from || runInfo.to != runInfo.run.length()))
        codePathToUse = ComplexPath;

    if (codePathToUse != ComplexPath)
        return drawSimpleText(context, runInfo, point);

    return drawComplexText(context, runInfo, point);
}
void RenderSVGInlineText::computeNewScaledFontForStyle(const RenderObject& renderer, const RenderStyle& style, float& scalingFactor, FontCascade& scaledFont)
{
    // Alter font-size to the right on-screen value to avoid scaling the glyphs themselves, except when GeometricPrecision is specified
    scalingFactor = SVGRenderingContext::calculateScreenFontSizeScalingFactor(renderer);
    if (scalingFactor == 1 || !scalingFactor || style.fontDescription().textRenderingMode() == GeometricPrecision) {
        scalingFactor = 1;
        scaledFont = style.fontCascade();
        return;
    }

    FontDescription fontDescription(style.fontDescription());

    // FIXME: We need to better handle the case when we compute very small fonts below (below 1pt).
    fontDescription.setComputedSize(Style::computedFontSizeFromSpecifiedSizeForSVGInlineText(fontDescription.computedSize(), fontDescription.isAbsoluteSize(), scalingFactor, renderer.document()));

    scaledFont = FontCascade(fontDescription, 0, 0);
    scaledFont.update(&renderer.document().fontSelector());
}
Example #12
0
const SimpleFontData* FontCache::getFontDataForCharacters(const Font& font, const UChar* characters, int length)
{
    String familyName;
    WCHAR name[LF_FACESIZE];

    UChar character = characters[0];
    const FontPlatformData& origFont = font.primaryFont()->fontDataForCharacter(character)->platformData();
    unsigned unicodeRange = findCharUnicodeRange(character);

#if defined(IMLANG_FONT_LINK) && (IMLANG_FONT_LINK == 2)
    if (IMLangFontLink2* langFontLink = getFontLinkInterface()) {
#else
    if (IMLangFontLink* langFontLink = getFontLinkInterface()) {
#endif
        HGDIOBJ oldFont = GetCurrentObject(g_screenDC, OBJ_FONT);
        HFONT hfont = 0;
        DWORD codePages = 0;
        UINT codePage = 0;
        // Try MLang font linking first.
        langFontLink->GetCharCodePages(character, &codePages);
        if (codePages && unicodeRange == cRangeSetCJK) {
            // The CJK character may belong to multiple code pages. We want to
            // do font linking against a single one of them, preferring the default
            // code page for the user's locale.
            const Vector<DWORD, 4>& CJKCodePageMasks = getCJKCodePageMasks();
            unsigned numCodePages = CJKCodePageMasks.size();
            for (unsigned i = 0; i < numCodePages; ++i) {
#if defined(IMLANG_FONT_LINK) && (IMLANG_FONT_LINK == 2)
                hfont = createMLangFont(langFontLink, g_screenDC, CJKCodePageMasks[i]);
#else
                hfont = createMLangFont(langFontLink, g_screenDC, origFont, CJKCodePageMasks[i]);
#endif
                if (!hfont)
                    continue;

                SelectObject(g_screenDC, hfont);
                GetTextFace(g_screenDC, LF_FACESIZE, name);

                if (hfont && !(codePages & CJKCodePageMasks[i])) {
                    // We asked about a code page that is not one of the code pages
                    // returned by MLang, so the font might not contain the character.
#if defined(IMLANG_FONT_LINK) && (IMLANG_FONT_LINK == 2)
                    if (!currentFontContainsCharacter(langFontLink, g_screenDC, character)) {
#else
                    if (!currentFontContainsCharacter(langFontLink, g_screenDC, hfont, character, name)) {
#endif
                        SelectObject(g_screenDC, oldFont);
                        langFontLink->ReleaseFont(hfont);
                        hfont = 0;
                        continue;
                    }
                }
                break;
            }
        } else {
#if defined(IMLANG_FONT_LINK) && (IMLANG_FONT_LINK == 2)
            hfont = createMLangFont(langFontLink, g_screenDC, codePages, character);
#else
            hfont = createMLangFont(langFontLink, g_screenDC, origFont, codePages);
#endif
            SelectObject(g_screenDC, hfont);
            GetTextFace(g_screenDC, LF_FACESIZE, name);
        }
        SelectObject(g_screenDC, oldFont);

        if (hfont) {
            familyName = name;
            langFontLink->ReleaseFont(hfont);
        } else
            FontPlatformData::mapKnownFont(codePages, familyName);
    }

    if (familyName.isEmpty())
        familyName = FontPlatformData::defaultFontFamily();

    if (!familyName.isEmpty()) {
        // FIXME: temporary workaround for Thai font problem
        FontDescription fontDescription(font.fontDescription());
        if (unicodeRange == cRangeThai && fontDescription.weight() > FontWeightNormal)
            fontDescription.setWeight(FontWeightNormal);

        FontPlatformData* result = getCachedFontPlatformData(fontDescription, familyName);
        if (result && result->hash() != origFont.hash()) {
            if (SimpleFontData* fontData = getCachedFontData(result, DoNotRetain))
                return fontData;
        }
    }

    return 0;
}
Example #13
0
void QtUiStyle::generateSettingsQss() const {
  QFile settingsQss(Quassel::configDirPath() + "settings.qss");
  if(!settingsQss.open(QFile::WriteOnly|QFile::Truncate)) {
    qWarning() << "Could not open" << settingsQss.fileName() << "for writing!";
    return;
  }
  QTextStream out(&settingsQss);

  out << "// Style settings made in Quassel's configuration dialog\n"
      << "// This file is automatically generated, do not edit\n";

  // ChatView
  ///////////
  QtUiStyleSettings fs("Fonts");
  if(fs.value("UseCustomChatViewFont").toBool())
    out << "\n// ChatView Font\n"
        << "ChatLine { " << fontDescription(fs.value("ChatView").value<QFont>()) << "; }\n";

  QtUiStyleSettings s("Colors");
  if(s.value("UseChatViewColors").toBool()) {
    out << "\n// Custom ChatView Colors\n"

        // markerline is special in that it always used to use a gradient, so we keep this behavior even with the new implementation
        << "Palette { marker-line: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 " << color("MarkerLine", s) << ", stop: 0.1 transparent); }\n"
        << "ChatView { background: " << color("ChatViewBackground", s) << "; }\n\n"
        << "ChatLine[label=\"highlight\"] {\n"
        << "  foreground: " << color("Highlight",s) << ";\n"
        << "  background: " << color("HighlightBackground", s) << ";\n"
        << "}\n\n"
        << "ChatLine::timestamp { foreground: " << color("Timestamp", s) << "; }\n\n"

        << msgTypeQss("plain", "ChannelMsg", s)
        << msgTypeQss("notice", "ServerMsg", s)
        << msgTypeQss("action", "ActionMsg", s)
        << msgTypeQss("nick", "CommandMsg", s)
        << msgTypeQss("mode", "CommandMsg", s)
        << msgTypeQss("join", "CommandMsg", s)
        << msgTypeQss("part", "CommandMsg", s)
        << msgTypeQss("quit", "CommandMsg", s)
        << msgTypeQss("kick", "CommandMsg", s)
        << msgTypeQss("kill", "CommandMsg", s)
        << msgTypeQss("server", "ServerMsg", s)
        << msgTypeQss("info", "ServerMsg", s)
        << msgTypeQss("error", "ErrorMsg", s)
        << msgTypeQss("daychange", "ServerMsg", s)
        << msgTypeQss("topic", "CommandMsg", s)
        << msgTypeQss("netsplit-join", "CommandMsg", s)
        << msgTypeQss("netsplit-quit", "CommandMsg", s)
        << msgTypeQss("invite", "CommandMsg", s)
        << "\n";
  }

  if(s.value("UseSenderColors").toBool()) {
    out << "\n// Sender Colors\n"
        << "ChatLine::sender#plain[sender=\"self\"] { foreground: " << color("SenderSelf", s) << "; }\n\n";

    for(int i = 0; i < 16; i++)
      out << senderQss(i, s);
  }

  // ItemViews
  ////////////

  UiStyleSettings uiFonts("Fonts");
  if(uiFonts.value("UseCustomItemViewFont").toBool()) {
    QString fontDesc = fontDescription(uiFonts.value("ItemView").value<QFont>());
    out << "\n// ItemView Font\n"
        << "ChatListItem { " << fontDesc << "; }\n"
        << "NickListItem { " << fontDesc << "; }\n\n";
  }

  UiStyleSettings uiColors("Colors");
  if(uiColors.value("UseBufferViewColors").toBool()) {
    out << "\n// BufferView Colors\n"
        << "ChatListItem { foreground: " << color("DefaultBuffer", uiColors) << "; }\n"
        << chatListItemQss("inactive", "InactiveBuffer", uiColors)
        << chatListItemQss("channel-event", "ActiveBuffer", uiColors)
        << chatListItemQss("unread-message", "UnreadBuffer", uiColors)
        << chatListItemQss("highlighted", "HighlightedBuffer", uiColors);
  }

  if(uiColors.value("UseNickViewColors").toBool()) {
    out << "\n// NickView Colors\n"
        << "NickListItem[type=\"category\"] { foreground: " << color("DefaultBuffer", uiColors) << "; }\n"
        << "NickListItem[type=\"user\"] { foreground: " << color("OnlineNick", uiColors) << "; }\n"
        << "NickListItem[type=\"user\", state=\"away\"] { foreground: " << color("AwayNick", uiColors) << "; }\n";
  }

  settingsQss.close();
}
Example #14
0
// TODO: This needs to be split into helper functions to better scope the
// inputs/outputs, and reduce duplicate code.
// This issue is tracked in https://bugs.webkit.org/show_bug.cgi?id=62989
void Font::drawGlyphs(GraphicsContext* gc, const SimpleFontData* font,
                      const GlyphBuffer& glyphBuffer,  int from, int numGlyphs,
                      const FloatPoint& point) const {
    COMPILE_ASSERT(sizeof(GlyphBufferGlyph) == sizeof(uint16_t), GlyphBufferGlyphSize_equals_uint16_t);

    bool shouldSmoothFonts = true;
    bool shouldAntialias = true;
    
    switch (fontDescription().fontSmoothing()) {
    case Antialiased:
        shouldSmoothFonts = false;
        break;
    case SubpixelAntialiased:
        break;
    case NoSmoothing:
        shouldAntialias = false;
        shouldSmoothFonts = false;
        break;
    case AutoSmoothing:
        // For the AutoSmooth case, don't do anything! Keep the default settings.
        break; 
    }
    
    if (!shouldUseSmoothing() || PlatformSupport::layoutTestMode())
        shouldSmoothFonts = false;

    const GlyphBufferGlyph* glyphs = glyphBuffer.glyphs(from);
    SkScalar x = SkFloatToScalar(point.x());
    SkScalar y = SkFloatToScalar(point.y());

    if (font->platformData().orientation() == Vertical)
        y += SkFloatToScalar(font->fontMetrics().floatAscent(IdeographicBaseline) - font->fontMetrics().floatAscent());
    // FIXME: text rendering speed:
    // Android has code in their WebCore fork to special case when the
    // GlyphBuffer has no advances other than the defaults. In that case the
    // text drawing can proceed faster. However, it's unclear when those
    // patches may be upstreamed to WebKit so we always use the slower path
    // here.
    const GlyphBufferAdvance* adv = glyphBuffer.advances(from);
    SkAutoSTMalloc<32, SkPoint> storage(numGlyphs);
    SkPoint* pos = storage.get();

    for (int i = 0; i < numGlyphs; i++) {
        pos[i].set(x, y);
        x += SkFloatToScalar(adv[i].width);
        y += SkFloatToScalar(adv[i].height);
    }

    SkCanvas* canvas = gc->platformContext()->canvas();
    if (font->platformData().orientation() == Vertical) {
        canvas->save();
        canvas->rotate(-90);
        SkMatrix rotator;
        rotator.reset();
        rotator.setRotate(90);
        rotator.mapPoints(pos, numGlyphs);
    }
    TextDrawingModeFlags textMode = gc->platformContext()->getTextDrawingMode();

    // We draw text up to two times (once for fill, once for stroke).
    if (textMode & TextModeFill) {
        SkPaint paint;
        gc->platformContext()->setupPaintForFilling(&paint);
        setupPaint(&paint, font, this, shouldAntialias, shouldSmoothFonts);
        gc->platformContext()->adjustTextRenderMode(&paint);
        paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);

        canvas->drawPosText(glyphs, numGlyphs * sizeof(uint16_t), pos, paint);
    }

    if ((textMode & TextModeStroke)
        && gc->platformContext()->getStrokeStyle() != NoStroke
        && gc->platformContext()->getStrokeThickness() > 0) {

        SkPaint paint;
        gc->platformContext()->setupPaintForStroking(&paint, 0, 0);
        setupPaint(&paint, font, this, shouldAntialias, shouldSmoothFonts);
        gc->platformContext()->adjustTextRenderMode(&paint);
        paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);

        if (textMode & TextModeFill) {
            // If we also filled, we don't want to draw shadows twice.
            // See comment in FontChromiumWin.cpp::paintSkiaText() for more details.
            paint.setLooper(0);
        }

        canvas->drawPosText(glyphs, numGlyphs * sizeof(uint16_t), pos, paint);
    }
    if (font->platformData().orientation() == Vertical)
        canvas->restore();
}
Example #15
0
void Font::drawGlyphs(GraphicsContext* graphicsContext, const SimpleFontData* font, const GlyphBuffer& glyphBuffer,
                      int from, int numGlyphs, const FloatPoint& point) const
{
    CGContextRef cgContext = graphicsContext->platformContext();
    bool shouldUseFontSmoothing = WebCoreShouldUseFontSmoothing();

    switch(fontDescription().fontSmoothing()) {
    case Antialiased: {
        graphicsContext->setShouldAntialias(true);
        shouldUseFontSmoothing = false;
        break;
    }
    case SubpixelAntialiased: {
        graphicsContext->setShouldAntialias(true);
        shouldUseFontSmoothing = true;
        break;
    }
    case NoSmoothing: {
        graphicsContext->setShouldAntialias(false);
        shouldUseFontSmoothing = false;
        break;
    }
    case AutoSmoothing: {
        // For the AutoSmooth case, don't do anything! Keep the default settings.
        break;
    }
    default:
        ASSERT_NOT_REACHED();
    }

    if (font->platformData().useGDI() && !shouldUseFontSmoothing) {
        drawGDIGlyphs(graphicsContext, font, glyphBuffer, from, numGlyphs, point);
        return;
    }

    uint32_t oldFontSmoothingStyle = wkSetFontSmoothingStyle(cgContext, shouldUseFontSmoothing);

    const FontPlatformData& platformData = font->platformData();

    CGContextSetFont(cgContext, platformData.cgFont());

    CGAffineTransform matrix = CGAffineTransformIdentity;
    matrix.b = -matrix.b;
    matrix.d = -matrix.d;

    if (platformData.syntheticOblique()) {
        static float skew = -tanf(syntheticObliqueAngle * piFloat / 180.0f);
        matrix = CGAffineTransformConcat(matrix, CGAffineTransformMake(1, 0, skew, 1, 0, 0));
    }

    CGContextSetTextMatrix(cgContext, matrix);

    // Uniscribe gives us offsets to help refine the positioning of combining glyphs.
    FloatSize translation = glyphBuffer.offsetAt(from);

    CGContextSetFontSize(cgContext, platformData.size());
    wkSetCGContextFontRenderingStyle(cgContext, font->isSystemFont(), false, font->platformData().useGDI());

    FloatSize shadowOffset;
    float shadowBlur;
    Color shadowColor;
    ColorSpace shadowColorSpace;
    graphicsContext->getShadow(shadowOffset, shadowBlur, shadowColor, shadowColorSpace);

    bool hasSimpleShadow = graphicsContext->textDrawingMode() == TextModeFill && shadowColor.isValid() && !shadowBlur && (!graphicsContext->shadowsIgnoreTransforms() || graphicsContext->getCTM().isIdentityOrTranslationOrFlipped());
    if (hasSimpleShadow) {
        // Paint simple shadows ourselves instead of relying on CG shadows, to avoid losing subpixel antialiasing.
        graphicsContext->clearShadow();
        Color fillColor = graphicsContext->fillColor();
        Color shadowFillColor(shadowColor.red(), shadowColor.green(), shadowColor.blue(), shadowColor.alpha() * fillColor.alpha() / 255);
        graphicsContext->setFillColor(shadowFillColor, ColorSpaceDeviceRGB);
        float shadowTextX = point.x() + translation.width() + shadowOffset.width();
        // If shadows are ignoring transforms, then we haven't applied the Y coordinate flip yet, so down is negative.
        float shadowTextY = point.y() + translation.height() + shadowOffset.height() * (graphicsContext->shadowsIgnoreTransforms() ? -1 : 1);
        CGContextSetTextPosition(cgContext, shadowTextX, shadowTextY);
        CGContextShowGlyphsWithAdvances(cgContext, glyphBuffer.glyphs(from), glyphBuffer.advances(from), numGlyphs);
        if (font->syntheticBoldOffset()) {
            CGContextSetTextPosition(cgContext, point.x() + translation.width() + shadowOffset.width() + font->syntheticBoldOffset(), point.y() + translation.height() + shadowOffset.height());
            CGContextShowGlyphsWithAdvances(cgContext, glyphBuffer.glyphs(from), glyphBuffer.advances(from), numGlyphs);
        }
        graphicsContext->setFillColor(fillColor, ColorSpaceDeviceRGB);
    }

    CGContextSetTextPosition(cgContext, point.x() + translation.width(), point.y() + translation.height());
    CGContextShowGlyphsWithAdvances(cgContext, glyphBuffer.glyphs(from), glyphBuffer.advances(from), numGlyphs);
    if (font->syntheticBoldOffset()) {
        CGContextSetTextPosition(cgContext, point.x() + translation.width() + font->syntheticBoldOffset(), point.y() + translation.height());
        CGContextShowGlyphsWithAdvances(cgContext, glyphBuffer.glyphs(from), glyphBuffer.advances(from), numGlyphs);
    }

    if (hasSimpleShadow)
        graphicsContext->setShadow(shadowOffset, shadowBlur, shadowColor, ColorSpaceDeviceRGB);

    wkRestoreFontSmoothingStyle(cgContext, oldFontSmoothingStyle);
}
Example #16
0
int RenderStyle::fontSize() const { return fontDescription().computedPixelSize(); }
Example #17
0
PassRefPtr<SimpleFontData> FontCache::systemFallbackForCharacters(const FontDescription& description, const SimpleFontData* originalFontData, bool, const UChar* characters, int length)
{
    String familyName;
    WCHAR name[LF_FACESIZE];

    UChar character = characters[0];
    const FontPlatformData& origFont = originalFontData->platformData();

    if (IMLangFontLinkType* langFontLink = getFontLinkInterface()) {
        HGDIOBJ oldFont = GetCurrentObject(g_screenDC, OBJ_FONT);
        HFONT hfont = 0;
        DWORD codePages = 0;
        UINT codePage = 0;
        // Try MLang font linking first.
        langFontLink->GetCharCodePages(character, &codePages);
        if (codePages && u_getIntPropertyValue(character, UCHAR_UNIFIED_IDEOGRAPH)) {
            // The CJK character may belong to multiple code pages. We want to
            // do font linking against a single one of them, preferring the default
            // code page for the user's locale.
            const Vector<DWORD, 4>& CJKCodePageMasks = getCJKCodePageMasks();
            unsigned numCodePages = CJKCodePageMasks.size();
            for (unsigned i = 0; i < numCodePages; ++i) {
                hfont = createMLangFont(langFontLink, g_screenDC, origFont, CJKCodePageMasks[i]);
                if (!hfont)
                    continue;

                SelectObject(g_screenDC, hfont);
                GetTextFace(g_screenDC, LF_FACESIZE, name);

                if (hfont && !(codePages & CJKCodePageMasks[i])) {
                    // We asked about a code page that is not one of the code pages
                    // returned by MLang, so the font might not contain the character.
                    if (!currentFontContainsCharacter(langFontLink, g_screenDC, hfont, character, name))
                    {
                        SelectObject(g_screenDC, oldFont);
                        langFontLink->ReleaseFont(hfont);
                        hfont = 0;
                        continue;
                    }
                }
                break;
            }
        } else {
            hfont = createMLangFont(langFontLink, g_screenDC, origFont, codePages, character);
            SelectObject(g_screenDC, hfont);
            GetTextFace(g_screenDC, LF_FACESIZE, name);
        }
        SelectObject(g_screenDC, oldFont);

        if (hfont) {
            familyName = name;
            langFontLink->ReleaseFont(hfont);
        } else
            FontPlatformData::mapKnownFont(codePages, familyName);
    }

    if (familyName.isEmpty())
        familyName = FontPlatformData::defaultFontFamily();

    if (!familyName.isEmpty()) {
        // FIXME: temporary workaround for Thai font problem
        FontDescription fontDescription(description);
        if (ublock_getCode(c) == UBLOCK_THAI && fontDescription.weight() > FontWeightNormal)
            fontDescription.setWeight(FontWeightNormal);

        FontPlatformData* result = getCachedFontPlatformData(fontDescription, familyName);
        if (result && result->hash() != origFont.hash()) {
            if (RefPtr<SimpleFontData> fontData = getCachedFontData(result, DoNotRetain))
                return fontData.release();
        }
    }

    return 0;
}
Example #18
0
FontWeight RenderStyle::fontWeight() const { return fontDescription().weight(); }
Example #19
0
void QtUiStyle::generateSettingsQss() const
{
    QFile settingsQss(Quassel::configDirPath() + "settings.qss");

    if (!settingsQss.open(QFile::WriteOnly | QFile::Truncate)) {
        qWarning() << "Could not open" << settingsQss.fileName() << "for writing!";
        return;
    }
    QTextStream out(&settingsQss);

    out << "// Style settings made in Quassel's configuration dialog\n"
        << "// This file is automatically generated, do not edit\n";

    // ChatView
    ///////////
    QtUiStyleSettings fs("Fonts");
    if (fs.value("UseCustomChatViewFont").toBool())
        out << "\n// ChatView Font\n"
            << "ChatLine { " << fontDescription(fs.value("ChatView").value<QFont>()) << "; }\n";

    QtUiStyleSettings s("Colors");
    if (s.value("UseChatViewColors").toBool()) {
        out << "\n// Custom ChatView Colors\n"

            // markerline is special in that it always used to use a gradient, so we keep this behavior even with the new implementation
            << "Palette { marker-line: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 " << color("MarkerLine", s)
            << ", stop: 0.1 transparent); }\n"
            << "ChatView { background: " << color("ChatViewBackground", s) << "; }\n\n"
            << "ChatLine[label=\"highlight\"] {\n"
            << "  foreground: " << color("Highlight", s) << ";\n"
            << "  background: " << color("HighlightBackground", s) << ";\n"
            << "}\n\n"
            << "ChatLine::timestamp { foreground: " << color("Timestamp", s) << "; }\n\n"

            << msgTypeQss("plain", "ChannelMsg", s) << msgTypeQss("notice", "ServerMsg", s) << msgTypeQss("action", "ActionMsg", s)
            << msgTypeQss("nick", "CommandMsg", s) << msgTypeQss("mode", "CommandMsg", s) << msgTypeQss("join", "CommandMsg", s)
            << msgTypeQss("part", "CommandMsg", s) << msgTypeQss("quit", "CommandMsg", s) << msgTypeQss("kick", "CommandMsg", s)
            << msgTypeQss("kill", "CommandMsg", s) << msgTypeQss("server", "ServerMsg", s) << msgTypeQss("info", "ServerMsg", s)
            << msgTypeQss("error", "ErrorMsg", s) << msgTypeQss("daychange", "ServerMsg", s) << msgTypeQss("topic", "CommandMsg", s)
            << msgTypeQss("netsplit-join", "CommandMsg", s) << msgTypeQss("netsplit-quit", "CommandMsg", s)
            << msgTypeQss("invite", "CommandMsg", s) << "\n";
    }

    if (s.value("UseSenderColors", true).toBool()) {
        out << "\n// Sender Colors\n";
        // Generate a color palette for easy reuse elsewhere
        // NOTE: A color palette is not a complete replacement for specifying the colors below, as
        // specifying the colors one-by-one instead of with QtUi::style()->brush(...) makes it easy
        // to toggle the specific coloring of sender/nick at the cost of regenerating this file.
        // See UiStyle::ColorRole
        out << senderPaletteQss(s);

        out << "ChatLine::sender#plain[sender=\"self\"] { foreground: palette(sender-color-self); }\n\n";

        // Matches qssparser.cpp for UiStyle::PlainMsg
        for (int i = 0; i < defaultSenderColors.count(); i++)
            out << senderQss(i, "plain");

        // Only color the nicks in CTCP ACTIONs if sender colors are enabled
        if (s.value("UseSenderActionColors", true).toBool()) {
            // For action messages, color the 'sender' column -and- the nick itself
            out << "\n// Sender Nickname Colors for action messages\n"
                << "ChatLine::sender#action[sender=\"self\"] { foreground: palette(sender-color-self); }\n"
                << "ChatLine::nick#action[sender=\"self\"] { foreground: palette(sender-color-self); }\n\n";

            // Matches qssparser.cpp for UiStyle::ActionMsg
            for (int i = 0; i < defaultSenderColors.count(); i++)
                out << senderQss(i, "action", true);
        }

        // Only color the nicks in CTCP ACTIONs if sender colors are enabled
        if (s.value("UseNickGeneralColors", true).toBool()) {
            // For action messages, color the 'sender' column -and- the nick itself
            out << "\n// Nickname colors for all messages\n"
                << "ChatLine::nick[sender=\"self\"] { foreground: palette(sender-color-self); }\n\n";

            // Matches qssparser.cpp for any style of message (UiStyle::...)
            for (int i = 0; i < defaultSenderColors.count(); i++)
                out << nickQss(i);
        }
    }

    // ItemViews
    ////////////

    UiStyleSettings uiFonts("Fonts");
    if (uiFonts.value("UseCustomItemViewFont").toBool()) {
        QString fontDesc = fontDescription(uiFonts.value("ItemView").value<QFont>());
        out << "\n// ItemView Font\n"
            << "ChatListItem { " << fontDesc << "; }\n"
            << "NickListItem { " << fontDesc << "; }\n\n";
    }

    UiStyleSettings uiColors("Colors");
    if (uiColors.value("UseBufferViewColors").toBool()) {
        out << "\n// BufferView Colors\n"
            << "ChatListItem { foreground: " << color("DefaultBuffer", uiColors) << "; }\n"
            << chatListItemQss("inactive", "InactiveBuffer", uiColors) << chatListItemQss("channel-event", "ActiveBuffer", uiColors)
            << chatListItemQss("unread-message", "UnreadBuffer", uiColors) << chatListItemQss("highlighted", "HighlightedBuffer", uiColors);
    }

    if (uiColors.value("UseNickViewColors").toBool()) {
        out << "\n// NickView Colors\n"
            << "NickListItem[type=\"category\"] { foreground: " << color("DefaultBuffer", uiColors) << "; }\n"
            << "NickListItem[type=\"user\"] { foreground: " << color("OnlineNick", uiColors) << "; }\n"
            << R"(NickListItem[type="user", state="away"] { foreground: )" << color("AwayNick", uiColors) << "; }\n";
    }
Example #20
0
float RenderStyle::computedFontSize() const { return fontDescription().computedSize(); }
Example #21
0
void Font::drawTextUsingSVGFont(GraphicsContext* context, const TextRun& run, 
                                const FloatPoint& point, int from, int to) const
{
    SVGFontElement* fontElement = 0;
    SVGFontFaceElement* fontFaceElement = 0;

    if (const SVGFontData* fontData = svgFontAndFontFaceElementForFontData(primaryFont(), fontFaceElement, fontElement)) {
        if (!fontElement)
            return;

        SVGTextRunWalkerDrawTextData data;
        FloatPoint currentPoint = point;
        float scale = convertEmUnitToPixel(size(), fontFaceElement->unitsPerEm(), 1.0f);

        SVGPaintServer* activePaintServer = run.activePaintServer();

        // If renderObject is not set, we're dealing for HTML text rendered using SVG Fonts.
        if (!run.referencingRenderObject()) {
            ASSERT(!activePaintServer);

            // TODO: We're only supporting simple filled HTML text so far.
            SVGPaintServerSolid* solidPaintServer = SVGPaintServer::sharedSolidPaintServer();
            solidPaintServer->setColor(context->fillColor());

            activePaintServer = solidPaintServer;
        }

        ASSERT(activePaintServer);

        int charsConsumed;
        String glyphName;
        bool isVerticalText = false;
        float xStartOffset = floatWidthOfSubStringUsingSVGFont(this, run, 0, run.rtl() ? to : 0, run.rtl() ? run.length() : from, charsConsumed, glyphName);
        FloatPoint glyphOrigin;

        String language;

        // TODO: language matching & svg glyphs should be possible for HTML text, too.
        if (run.referencingRenderObject()) {
            isVerticalText = isVerticalWritingMode(run.referencingRenderObject()->style()->svgStyle());    

            if (SVGElement* element = static_cast<SVGElement*>(run.referencingRenderObject()->element()))
                language = element->getAttribute(XMLNames::langAttr);
        }

        if (!isVerticalText) {
            glyphOrigin.setX(fontData->horizontalOriginX() * scale);
            glyphOrigin.setY(fontData->horizontalOriginY() * scale);
        }

        data.extraCharsAvailable = 0;
        data.charsConsumed = 0;

        SVGTextRunWalker<SVGTextRunWalkerDrawTextData> runWalker(fontData, fontElement, data, drawTextUsingSVGFontCallback, drawTextMissingGlyphCallback);
        runWalker.walk(run, isVerticalText, language, from, to);

        SVGPaintTargetType targetType = context->textDrawingMode() == cTextStroke ? ApplyToStrokeTargetType : ApplyToFillTargetType;

        unsigned numGlyphs = data.glyphIdentifiers.size();
        unsigned fallbackCharacterIndex = 0;
        for (unsigned i = 0; i < numGlyphs; ++i) {
            const SVGGlyphIdentifier& identifier = data.glyphIdentifiers[run.rtl() ? numGlyphs - i - 1 : i];
            if (identifier.isValid) {
                // FIXME: Support arbitary SVG content as glyph (currently limited to <glyph d="..."> situations).
                if (!identifier.pathData.isEmpty()) {
                    context->save();

                    if (isVerticalText) {
                        glyphOrigin.setX(identifier.verticalOriginX * scale);
                        glyphOrigin.setY(identifier.verticalOriginY * scale);
                    }

                    context->translate(xStartOffset + currentPoint.x() + glyphOrigin.x(), currentPoint.y() + glyphOrigin.y());
                    context->scale(FloatSize(scale, -scale));

                    context->beginPath();
                    context->addPath(identifier.pathData);

                    if (activePaintServer->setup(context, run.referencingRenderObject(), targetType)) {
                        // Spec: Any properties specified on a text elements which represents a length, such as the
                        // 'stroke-width' property, might produce surprising results since the length value will be
                        // processed in the coordinate system of the glyph. (TODO: What other lengths? miter-limit? dash-offset?)
                        if (targetType == ApplyToStrokeTargetType && scale != 0.0f)
                            context->setStrokeThickness(context->strokeThickness() / scale);

                        activePaintServer->renderPath(context, run.referencingRenderObject(), targetType);
                        activePaintServer->teardown(context, run.referencingRenderObject(), targetType);
                    }

                    context->restore();
                }

                if (isVerticalText)
                    currentPoint.move(0.0f, identifier.verticalAdvanceY * scale);
                else
                    currentPoint.move(identifier.horizontalAdvanceX * scale, 0.0f);
            } else {
                // Handle system font fallback
                FontDescription fontDescription(context->font().fontDescription());
                fontDescription.setFamily(FontFamily());
                Font font(fontDescription, 0, 0); // spacing handled by SVG text code.
                font.update(context->font().fontSelector());

                TextRun fallbackCharacterRun(run);
                fallbackCharacterRun.setText(&data.fallbackCharacters[run.rtl() ? data.fallbackCharacters.size() - fallbackCharacterIndex - 1 : fallbackCharacterIndex], 1);
                font.drawText(context, fallbackCharacterRun, currentPoint);

                if (isVerticalText)
                    currentPoint.move(0.0f, font.floatWidth(fallbackCharacterRun));
                else
                    currentPoint.move(font.floatWidth(fallbackCharacterRun), 0.0f);

                fallbackCharacterIndex++;
            }
        }
    }
}
Example #22
0
FontStretch RenderStyle::fontStretch() const { return fontDescription().stretch(); }
Example #23
0
void Font::willUseFontData() const
{
    const FontFamily& family = fontDescription().family();
    if (m_fontFallbackList && m_fontFallbackList->fontSelector() && !family.familyIsEmpty())
        m_fontFallbackList->fontSelector()->willUseFontData(fontDescription(), family.family());
}
Example #24
0
float RenderStyle::specifiedFontSize() const { return fontDescription().specifiedSize(); }