Commit 1793b51e authored by Julian Wolff's avatar Julian Wolff Committed by David Edmundson
Browse files

add preview images to fonts kcm

Summary:
The fonts kcm offers different font rendering settings. Currently, one needs to apply the settings and
reopen the application to see the changes.
This patch adds a way to render fonts at different settings (mostly based on existing code in kfontinst) and
adds preview images to the sub-pixel and hinting comboboxes.

This is part of a planned redesign of the fonts kcm. See the discussion in https://phabricator.kde.org/T7927

Test Plan:
Open the fonts kcm, click on the sub-pixel combobox. The preview images should look different.

{F5743556}

Reviewers: #plasma, harmathy, mart, davidedmundson, ngraham

Reviewed By: #plasma, harmathy, mart, ngraham

Subscribers: ngraham, davidedmundson, abetts, broulik, plasma-devel

Tags: #plasma

Differential Revision: https://phabricator.kde.org/D11064
parent e6642a95
......@@ -60,11 +60,12 @@ if (SYNAPTICS_FOUND AND X11_Xinput_FOUND)
add_subdirectory(touchpad)
endif()
if(FONTCONFIG_FOUND AND FREETYPE_FOUND)
add_subdirectory( kfontinst )
endif()
if( FREETYPE_FOUND )
if(FONTCONFIG_FOUND )
add_subdirectory( fonts )
endif()
endif()
if(FONTCONFIG_FOUND AND FREETYPE_FOUND)
add_subdirectory( kfontinst )
endif()
......@@ -8,7 +8,9 @@ include_directories(${FREETYPE_INCLUDE_DIRS})
########### next target ###############
set(kcm_fonts_PART_SRCS ../krdb/krdb.cpp fonts.cpp)
include_directories(../kfontinst/lib)
set(kcm_fonts_PART_SRCS ../krdb/krdb.cpp previewrenderengine.cpp previewimageprovider.cpp fonts.cpp ../kfontinst/lib/FcEngine.cpp)
if(X11_FOUND)
set(kcm_fonts_PART_SRCS ${kcm_fonts_PART_SRCS} ${libkxftconfig_SRCS})
......@@ -19,8 +21,7 @@ qt5_add_dbus_interface(kcm_fonts_PART_SRCS ${klauncher_xml} klauncher_iface)
add_library(kcm_fonts MODULE ${kcm_fonts_PART_SRCS})
target_link_libraries(kcm_fonts Qt5::DBus Qt5::Xml KF5::KCMUtils KF5::I18n KF5::KDELibs4Support ${FREETYPE_LIBRARIES})
target_link_libraries(kcm_fonts Qt5::DBus Qt5::Xml KF5::KCMUtils KF5::I18n KF5::KDELibs4Support ${FREETYPE_LIBRARIES} kfontinst)
if(X11_FOUND)
target_link_libraries(kcm_fonts
......@@ -34,7 +35,7 @@ if(X11_FOUND)
target_link_libraries(kcm_fonts ${FONTCONFIG_LIBRARIES})
endif()
target_link_libraries(kcm_fonts ${X11_LIBRARIES})
target_link_libraries(kcm_fonts ${X11_LIBRARIES} ${X11_Xft_LIB})
endif()
kcoreaddons_desktop_to_json(kcm_fonts "kcm_fonts.desktop")
......
......@@ -47,6 +47,7 @@
#include <KMessageBox>
#include "../krdb/krdb.h"
#include "previewimageprovider.h"
/**** DLL Interface ****/
K_PLUGIN_FACTORY_WITH_JSON(KFontsFactory, "kcm_fonts.json", registerPlugin<KFonts>();)
......@@ -499,6 +500,8 @@ void KFonts::load()
cg = KConfigGroup(config, "WM");
m_windowTitleFont = m_windowTitleFontOriginal = nearestExistingFont(cg.readEntry("activeFont", m_defaultFont));
engine()->addImageProvider("preview", new PreviewImageProvider(generalFont()));
emit generalFontChanged();
emit fixedWidthFontChanged();
emit smallFontChanged();
......
......@@ -138,6 +138,32 @@ KCM.SimpleKCM {
model: kcm.fontAASettings.subPixelOptionsModel
textRole: "display"
enabled: antiAliasingComboBox.currentIndex == 0
popup.height: popup.implicitHeight
delegate: QtControls.ItemDelegate {
id: subPixelDelegate
onWidthChanged: {
subPixelCombo.popup.width = Math.max(subPixelCombo.popup.width, width)
}
contentItem: ColumnLayout {
id: subPixelLayout
Kirigami.Heading {
id: subPixelComboText
text: model.display
level: 5
}
Image {
id: subPixelComboImage
source: "image://preview/" + model.index + "_" + kcm.fontAASettings.hintingCurrentIndex + ".png"
// Setting sourceSize here is necessary as a workaround for QTBUG-38127
//
// With this bug, images requested from a QQuickImageProvider have an incorrect scale with devicePixelRatio != 1 when sourceSize is not set.
//
// TODO: Check if QTBUG-38127 is fixed and remove the next two lines.
sourceSize.width: 1
sourceSize.height: 1
}
}
}
}
QtControls.ComboBox {
......@@ -149,6 +175,32 @@ KCM.SimpleKCM {
model: kcm.fontAASettings.hintingOptionsModel
textRole: "display"
enabled: antiAliasingComboBox.currentIndex == 0
popup.height: popup.implicitHeight
delegate: QtControls.ItemDelegate {
id: hintingDelegate
onWidthChanged: {
hintingCombo.popup.width = Math.max(hintingCombo.popup.width, width)
}
contentItem: ColumnLayout {
id: hintingLayout
Kirigami.Heading {
id: hintingComboText
text: model.display
level: 5
}
Image {
id: hintingComboImage
source: "image://preview/" + kcm.fontAASettings.subPixelCurrentIndex + "_" + model.index + ".png"
// Setting sourceSize here is necessary as a workaround for QTBUG-38127
//
// With this bug, images requested from a QQuickImageProvider have an incorrect scale with devicePixelRatio != 1 when sourceSize is not set.
//
// TODO: Check if QTBUG-38127 is fixed and remove the next two lines.
sourceSize.width: 1
sourceSize.height: 1
}
}
}
}
RowLayout {
......
/*
Copyright (c) 2018 Julian Wolff <wolff@julianwolff.de>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public License
along with this library; see the file COPYING.LIB. If not, write to
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA.
*/
#include <QApplication>
#include <QPainter>
#include <QPalette>
#include "kxftconfig.h"
#include "previewimageprovider.h"
#include "previewrenderengine.h"
QImage combineImages(const QList<QImage>& images, const QColor& bgnd, int spacing=0)
{
int width = 0;
int height = 0;
QImage::Format format = QImage::Format_Invalid;
int devicePixelRatio = 1;
for(const auto& image : images) {
if(width < image.width()) {
width = image.width();
}
height += image.height() + spacing;
format = image.format();
devicePixelRatio = image.devicePixelRatio();
}
height -= spacing;
// To correctly align the image pixels on a high dpi display,
// the image dimensions need to be a multiple of devicePixelRatio
width = (width + devicePixelRatio - 1) / devicePixelRatio * devicePixelRatio;
height = (height + devicePixelRatio - 1) / devicePixelRatio * devicePixelRatio;
QImage combinedImage(width, height, format);
combinedImage.setDevicePixelRatio(devicePixelRatio);
combinedImage.fill(bgnd);
int offset = 0;
QPainter p(&combinedImage);
for(const auto& image : images) {
p.drawImage(0, offset, image);
offset += (image.height() + spacing) / devicePixelRatio;
}
return combinedImage;
}
PreviewImageProvider::PreviewImageProvider(const QFont& font)
: QQuickImageProvider(QQuickImageProvider::Image)
, m_font(font)
{
}
QImage PreviewImageProvider::requestImage(const QString &id, QSize *size, const QSize &requestedSize)
{
int subPixelIndex = 0;
int hintingIndex = 0;
const auto idpart = id.splitRef(QLatin1Char('.'))[0];
const auto sections = idpart.split(QLatin1Char('_'));
if (sections.size() >= 2) {
subPixelIndex = sections[0].toInt();
hintingIndex = sections[1].toInt();
}
KXftConfig xft;
KXftConfig::AntiAliasing::State oldAntialiasing = xft.getAntiAliasing();
double oldStart,oldEnd;
xft.getExcludeRange(oldStart, oldEnd);
KXftConfig::SubPixel::Type oldSubPixelType;
xft.getSubPixelType(oldSubPixelType);
KXftConfig::Hint::Style oldHintStyle;
xft.getHintStyle(oldHintStyle);
xft.setAntiAliasing(KXftConfig::AntiAliasing::Enabled);
xft.setExcludeRange(0, 0);
KXftConfig::SubPixel::Type subPixelType = (KXftConfig::SubPixel::Type)subPixelIndex;
xft.setSubPixelType(subPixelType);
KXftConfig::Hint::Style hintStyle = (KXftConfig::Hint::Style)hintingIndex;
xft.setHintStyle(hintStyle);
xft.apply();
QColor text(QApplication::palette().color(QPalette::Text));
QColor bgnd(QApplication::palette().color(QPalette::Window));
PreviewRenderEngine eng(true);
QList<QImage> lines;
lines << eng.drawAutoSize(m_font, text, bgnd, eng.getDefaultPreviewString());
QImage img = combineImages(lines, bgnd, lines[0].height()*.25);
xft.setAntiAliasing(oldAntialiasing);
xft.setExcludeRange(oldStart, oldEnd);
xft.setSubPixelType(oldSubPixelType);
xft.setHintStyle(oldHintStyle);
*size = img.size();
return img;
}
/*
Copyright (c) 2018 Julian Wolff <wolff@julianwolff.de>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public License
along with this library; see the file COPYING.LIB. If not, write to
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA.
*/
#ifndef __PREVIEW_IMAGE_PROVIDER_H__
#define __PREVIEW_IMAGE_PROVIDER_H__
#include <QQuickImageProvider>
#include <QFont>
class PreviewImageProvider : public QQuickImageProvider
{
public:
PreviewImageProvider(const QFont& font);
QImage requestImage(const QString &id, QSize *size, const QSize &requestedSize);
private:
QFont m_font;
};
#endif // __PREVIEW_IMAGE_PROVIDER_H__
/*
Copyright (c) 2018 Julian Wolff <wolff@julianwolff.de>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public License
along with this library; see the file COPYING.LIB. If not, write to
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA.
*/
#include "kxftconfig.h"
#include "previewrenderengine.h"
#include "Fc.h"
#include <QApplication>
#include <QDesktopWidget>
#include <QX11Info>
#include <X11/Xft/Xft.h>
#ifdef HAVE_FONTCONFIG
static int qtToFcWeight(int weight)
{
switch(weight)
{
case 0:
return FC_WEIGHT_THIN;
case QFont::Light>>1:
return FC_WEIGHT_EXTRALIGHT;
case QFont::Light:
return FC_WEIGHT_LIGHT;
default:
case QFont::Normal:
return FC_WEIGHT_REGULAR;
case (QFont::Normal+QFont::DemiBold)>>1:
#ifdef KFI_HAVE_MEDIUM_WEIGHT
return FC_WEIGHT_MEDIUM;
#endif
case QFont::DemiBold:
return FC_WEIGHT_DEMIBOLD;
case QFont::Bold:
return FC_WEIGHT_BOLD;
case (QFont::Bold+QFont::Black)>>1:
return FC_WEIGHT_EXTRABOLD;
case QFont::Black:
return FC_WEIGHT_BLACK;
}
}
#ifndef KFI_FC_NO_WIDTHS
static int qtToFcWidth(int weight)
{
switch(weight)
{
case QFont::UltraCondensed:
return KFI_FC_WIDTH_ULTRACONDENSED;
case QFont::ExtraCondensed:
return KFI_FC_WIDTH_EXTRACONDENSED;
case QFont::Condensed:
return KFI_FC_WIDTH_CONDENSED;
case QFont::SemiCondensed:
return KFI_FC_WIDTH_SEMICONDENSED;
default:
case QFont::Unstretched:
return KFI_FC_WIDTH_NORMAL;
case QFont::SemiExpanded:
return KFI_FC_WIDTH_SEMIEXPANDED;
case QFont::Expanded:
return KFI_FC_WIDTH_EXPANDED;
case QFont::ExtraExpanded:
return KFI_FC_WIDTH_EXTRAEXPANDED;
case QFont::UltraExpanded:
return KFI_FC_WIDTH_ULTRAEXPANDED;
}
}
#endif
static bool qtToFcSlant(int slant)
{
switch(slant)
{
default:
case QFont::StyleNormal:
return FC_SLANT_ROMAN;
case QFont::StyleItalic:
return FC_SLANT_ITALIC;
case QFont::StyleOblique:
return FC_SLANT_OBLIQUE;
}
}
static quint32 qtToFcStyle(const QFont &font)
{
return KFI::FC::createStyleVal(
qtToFcWeight(font.weight()),
qtToFcWidth(font.stretch()),
qtToFcSlant(font.style())
);
}
PreviewRenderEngine::PreviewRenderEngine(bool init)
: CFcEngine(init)
{
if(init)
FcInitReinitialize();
}
PreviewRenderEngine::~PreviewRenderEngine()
{
}
QImage PreviewRenderEngine::drawAutoSize(const QFont &font, const QColor &txt, const QColor &bgnd, const QString &text)
{
const QString& name = font.family();
const quint32 style = qtToFcStyle(font);
int faceNo = 0;
double ratio = QApplication::desktop()->screen()->devicePixelRatio();
double dpi = QX11Info::appDpiY();
int fSize((int)(((font.pointSizeF()*dpi*ratio)/72.0)+0.5));
QImage image(draw(name, style, faceNo, txt, bgnd, fSize, text));
image.setDevicePixelRatio(ratio);
return image;
}
#endif // HAVE_FONTCONFIG
/*
Copyright (c) 2018 Julian Wolff <wolff@julianwolff.de>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public License
along with this library; see the file COPYING.LIB. If not, write to
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA.
*/
#ifndef __PREVIEW_RENDER_ENGINE_H
#define __PREVIEW_RENDER_ENGINE_H
#include "kxftconfig.h"
#include "FcEngine.h"
#ifdef HAVE_FONTCONFIG
#include <QImage>
class PreviewRenderEngine : public KFI::CFcEngine
{
public:
PreviewRenderEngine(bool init=true);
~PreviewRenderEngine();
QImage drawAutoSize(const QFont &font, const QColor &txt, const QColor &bgnd, const QString &text);
};
#endif // HAVE_FONTCONFIG
#endif // __PREVIEW_RENDER_ENGINE_H
......@@ -389,7 +389,7 @@ bool CFcEngine::Xft::drawString(XftFont *xftFont, const QString &text, int x, in
const FcChar16 *str=(FcChar16 *)(text.utf16());
XftTextExtents16(QX11Info::display(), xftFont, str, text.length(), &extents);
if(y+extents.height<h)
if(y+extents.height<=h)
XftDrawString16(itsDraw, &itsTxtColor, xftFont, x, y+extents.y, str, text.length());
if(extents.height>0)
{
......@@ -759,6 +759,95 @@ QImage CFcEngine::drawPreview(const QString &name, quint32 style, int faceNo, co
return img;
}
QImage CFcEngine::draw(const QString &name, quint32 style, int faceNo, const QColor &txt, const QColor &bgnd, int fSize, const QString &text_)
{
QImage img;
QString text = text_;
if(!name.isEmpty() &&
((name==itsName && style==itsStyle) ||
parse(name, style, faceNo)) )
{
getSizes();
if(itsSizes.size())
{
if(!itsScalable) // Then need to get nearest size...
{
int bSize=0;
for(int s=0; s<itsSizes.size(); ++s)
if (itsSizes[s]<=fSize || 0==bSize)
bSize=itsSizes[s];
fSize=bSize;
}
int h = fSize;
int w = 0;
XftFont *xftFont=getFont(fSize);
if(xftFont)
{
XGlyphInfo extents;
const FcChar16 *str=(FcChar16 *)(text.utf16());
XftTextExtents16(QX11Info::display(), xftFont, str, text.length(),
&extents);
h = extents.height;
w = extents.width;
bool needAlpha(bgnd.alpha()<255);
if(xft()->init(needAlpha ? Qt::black : txt, needAlpha ? Qt::white : bgnd, w, h))
{
bool rv=false;
if(hasStr(xftFont, text) || hasStr(xftFont, text=text.toUpper()) ||
hasStr(xftFont, text=text.toLower()))
{
XGlyphInfo extents;
const FcChar16 *str=(FcChar16 *)(text.utf16());
XftTextExtents16(QX11Info::display(), xftFont, str, text.length(),
&extents);
int x=0,
y=0;
rv=xft()->drawString(xftFont, text, x, y, h);
}
else
{
int x=0,
y=0;
QRect used;
rv=xft()->drawAllGlyphs(xftFont, h, x, y, w, h, true, text.length(), &used);
}
if(rv)
{
img=xft()->toImage(w, h);
if(!img.isNull())
{
img=img.copy(0, 0, w, h);
if(needAlpha)
setTransparentBackground(img, txt);
}
}
}
closeFont(xftFont);
}
}
}
return img;
}
QImage CFcEngine::draw(const QString &name, quint32 style, int faceNo, const QColor &txt, const QColor &bgnd,
int w, int h, bool thumb, const QList<TRange> &range, QList<TChar> *chars)
{
......
......@@ -71,13 +71,14 @@ class Q_DECL_EXPORT CFcEngine
static CFcEngine * instance();
CFcEngine(bool init=true);
~CFcEngine();
virtual ~CFcEngine();
void readConfig(KConfig &cfg);
void writeConfig(KConfig &cfg);
static void setDirty() { theirFcDirty=true; }
QImage drawPreview(const QString &name, quint32 style, int faceNo, const QColor &txt, const QColor &bgnd,
int h);
QImage draw(const QString &name, quint32 style, int faceNo, const QColor &txt, const QColor &bgnd, int fSize, const QString &text);
QImage draw(const QString &name, quint32 style, int faceNo, const QColor &txt, const QColor &bgnd,
int w, int h, bool thumb, const QList<TRange> &range=QList<TRange>(), QList<TChar> *chars=NULL);
int getNumIndexes() { return itsIndexCount; } // Only valid after draw has been called!
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment