Saturday, December 12, 2009

Wine Font Rendering Hiccups and Fixes

I have to admit that the default font rendering in Wine sucks. That is due to the disabled Sub Pixel Font Rendering in default Wine installation. Before we get into the fix, I'd like to highlight my system configuration first. Here it is:



  1. Operating System: Slamd64 12.1 with customized kernel 2.6.28.10

  2. Installed font rendering-related packages: FreeType 2.3.5, Fontconfig 2.4.2, Fontforge 20090923

  3. Wine version 1.1.33


I built Fontforge with the following slackbuild script:


#!/bin/sh

# Slackware build script for fontforge

# Copyright 2006-2008 Robby Workman Northport, Alabama, USA
# All rights reserved.
#
# Redistribution and use of this script, with or without modification, is
# permitted provided that the following conditions are met:
#
# 1. Redistributions of this script must retain the above copyright
# notice, this list of conditions and the following disclaimer.
#
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ''AS IS'' AND ANY EXPRESS OR IMPLIED
# WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
# EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
# OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
# OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
# ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

# Thanks to Eric Hameleers for some pointers on getting the fontforge.pc
# file right without too much manual intervention :-)

PRGNAM=fontforge
VERSION=20090923
ARCH=${ARCH:-x86_64}
BUILD=${BUILD:-1}
TAG=${TAG:-_SB64}

CWD=$(pwd)
TMP=${TMP:-/tmp/SB64}
PKG=$TMP/package-$PRGNAM
OUTPUT=${OUTPUT:-/tmp}

if [ "$ARCH" = "i486" ]; then
SLKCFLAGS="-O2 -march=i486 -mtune=i686"
elif [ "$ARCH" = "i686" ]; then
SLKCFLAGS="-O2 -march=i686 -mtune=i686"
elif [ "$ARCH" = "x86_64" ]; then
SLKCFLAGS="-O2 -fPIC"
fi

set -e

rm -rf $PKG
mkdir -p $TMP $PKG $OUTPUT
cd $TMP
rm -rf $PRGNAM-$VERSION
tar xvf $CWD/${PRGNAM}_full-${VERSION}.tar.bz2
cd $PRGNAM-$VERSION
chown -R root:root .
chmod -R u+w,go+r-w,a-s .

CFLAGS="$SLKCFLAGS" \
CXXFLAGS="$SLKCFLAGS" \
./configure \
--prefix=/usr \
--libdir=/usr/lib64 \
--mandir=/usr/man \
--with-x \
--with-pic \
--with-devicetables \
--with-freetype-src=/usr/include/freetype \
--without-python \
--disable-pyextension \
--enable-libff \
--enable-type3 \
--enable-tilepath \
--disable-debug \
--enable-static=no \
--enable-shared=yes \
--build=$ARCH-slamd64-linux

make
make prefix=$PKG/usr libdir=$PKG/usr/lib64 install

# Let's add the cidmaps if the user downloaded them
if [ -e $CWD/cidmaps.tgz ]; then
mkdir -p $PKG/usr/share/fontforge
tar xvf $CWD/cidmaps.tgz -C $PKG/usr/share/fontforge || exit 1
chmod 0644 $PKG/usr/share/fontforge/*.cidmap
chown root:root $PKG/usr/share/fontforge/*.cidmap
fi

( cd $PKG
find . | xargs file | grep "executable" | grep ELF | cut -f 1 -d : | xargs strip --strip-unneeded 2> /dev/null || true
find . | xargs file | grep "shared object" | grep ELF | cut -f 1 -d : | xargs strip --strip-unneeded 2> /dev/null
)

( cd $PKG/usr/man
find . -type f -exec gzip -9 {} \;
for i in $( find . -type l ); do ln -s $( readlink $i ).gz $i.gz ; rm $i ; done
)

mkdir -p $PKG/usr/doc/$PRGNAM-$VERSION
cp -a AUTHORS INSTALL LICENSE README-Unix.html README-unix VERSION \
$PKG/usr/doc/$PRGNAM-$VERSION
cat $CWD/$PRGNAM.SlackBuild > $PKG/usr/doc/$PRGNAM-$VERSION/$PRGNAM.SlackBuild
find $PKG/usr/doc -type f -exec chmod 644 {} \;

mkdir -p $PKG/install
cat $CWD/slack-desc > $PKG/install/slack-desc

cd $PKG
/sbin/makepkg -l y -c n $OUTPUT/$PRGNAM-$VERSION-$ARCH-$BUILD$TAG.tgz



The Wine installation is also custom compiled with the following script:


#!/bin/sh
# $Id: wine.SlackBuild,v 1.54 2009/09/14 20:51:17 root Exp root $
# Copyright 2006-2009 Eric Hameleers, Eindhoven, NL
# All rights reserved.
#
# Permission to use, copy, modify, and distribute this software for
# any purpose with or without fee is hereby granted, provided that
# the above copyright notice and this permission notice appear in all
# copies.
#
# THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
# WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
# IN NO EVENT SHALL THE AUTHORS AND COPYRIGHT HOLDERS AND THEIR
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
# SUCH DAMAGE.
# -----------------------------------------------------------------------------
# Slackware SlackBuild script
# ===========================
# By: Eric Hameleers
# For: wine
# Descr: Wine Is Not an Emulator
# URL: http://winehq.com/
# Needs: fontforge (builds better fonts when compiling wine)
# 1.1.29-1: 14/sep/2009 by Eric Hameleers
#
# Run 'sh wine.SlackBuild' to build a Slackware package.
# The package (.tgz) plus descriptive .txt file are created in /tmp .
# Install using 'installpkg'.
#
# -----------------------------------------------------------------------------

# Set initial variables:

PRGNAM=wine
SRCVER=${SRCVER:-"1.1.33"}
VERSION=$(echo $SRCVER | tr '-' '.')
ARCH=${ARCH:-"x86_64"}
BUILD=${BUILD:-1}
TAG=${TAG:-alien}

DOCS="ANNOUNCE AUTHORS COPYING.LIB ChangeLog LICENSE* README VERSION"

# Set the variable OPENGL to "NO" if you don't have a card that
# supports hardware accelerated OpenGL:
OPENGL=${OPENGL:-"YES"} # Use 'YES' not 'yes' : case-sensitive!

# If you set REQUIRE_FONTFORGE to "NO" then the script won't refuse to build
# wine in case you don't have fontforge installed (it is needed to
# generate the required base fonts).
REQUIRE_FONTFORGE=${REQUIRE_FONTFORGE:-"YES"}

# Where do we look for sources?
SRCDIR=$(cd $(dirname $0); pwd)

# Place to build (TMP) package (PKG) and output (OUTPUT) the program:
TMP=${TMP:-/tmp/build}
PKG=$TMP/package-$PRGNAM
OUTPUT=${OUTPUT:-/tmp}

SOURCE="$SRCDIR/${PRGNAM}-${SRCVER}.tar.bz2"
SRCURL="http://ibiblio.org/pub/linux/system/emulators/${PRGNAM}/${PRGNAM}-${SRCVER}.tar.bz2"

##
## --- with a little luck, you won't have to edit below this point --- ##
##

# Exit the script on errors:
set -e
trap 'echo "$0 FAILED on line $LINENO!" | tee $OUTPUT/error-${PRGNAM}.log' ERR
# Catch unitialized variables:
set -u
P1=${1:-1}

case "$ARCH" in
i486) SLKCFLAGS="-O2 -march=i486 -mtune=i686"
;;
s390) SLKCFLAGS="-O2"
;;
powerpc) SLKCFLAGS="-O2"
;;
x86_64) SLKCFLAGS="-O2 -fPIC"
;;
esac

# Prepare a sane build environment:
mkdir -p $TMP/tmp-$PRGNAM # location to build the source
rm -rf $TMP/tmp-$PRGNAM/* # remove the remnants of previous build and continue
mkdir -p $PKG # place for the package to be built
rm -rf $PKG/* # We always erase old package's contents
mkdir -p $OUTPUT # place for the package to be saved

# Source files availability:
if ! [ -f ${SOURCE} ]; then
if ! [ "x${SRCURL}" == "x" ]; then
# Check if the $SRCDIR is writable at all - if not, download to $OUTPUT
[ -w "$SRCDIR" ] || SOURCE="$OUTPUT/$(basename $SOURCE)"
echo "Source '$(basename ${SOURCE})' not available yet..."
echo "Will download file to $(dirname $SOURCE)"
wget -nv -T 20 -O "${SOURCE}" "${SRCURL}" || true
if [ $? -ne 0 -o ! -s "${SOURCE}" ]; then
echo "Downloading '$(basename ${SOURCE})' failed... aborting the build."
mv -f "${SOURCE}" "${SOURCE}".FAIL
exit 1
fi
else
echo "File '$(basename ${SOURCE})' not available... aborting the build."
exit 1
fi
fi

if [ "$P1" == "--download" ]; then
echo "Download complete."
exit 0
fi

# --- PACKAGE BUILDING ---

echo "++"
echo "|| $PRGNAM-$VERSION"
echo "++"

if ! which fontforge >/dev/null 2>&1 ; then
echo "##"
echo "## The 'fontforge' program does not seem to be installed."
echo "## Wine uses fontforge to generate several TTF fonts (tahoma,tahomabd,marlett)"
echo "## that your Windows programs may want to use!"
if [ "$REQUIRE_FONTFORGE" != "YES" ]; then
echo "##"
echo "## Continuing the build anyway, but you were warned..."
echo "## Sleeping for 5 seconds, press -C if you want to abort now."
echo "##"
sleep 5
else
echo "##"
echo "## Aborting the build - set the internal script variable:"
echo "##"
echo "## 'REQUIRE_FONTFORGE' to a value of 'NO'"
echo "##"
echo "## if you don't want to use fontforge to generate TTF fonts."
echo "##"
exit 1
fi
fi

cd $TMP/tmp-$PRGNAM

echo "Extracting the source archive(s) for $PRGNAM..."
tar -xvf ${SOURCE}
[ "$SRCVER" != "$VERSION" ] && mv ${PRGNAM}-${SRCVER} ${PRGNAM}-${VERSION}
cd ${PRGNAM}-${VERSION}
# Starting with openssl-0.9.8h, a typedef was introduced named "X509_EXTENSIONS"
# into openssl/x509.h. Unfortunately, wine uses a define of the same name
# in include/wincrypt.h. You may need this patch:
#patch -p0 < $SRCDIR/wine_openssl.patch chown -R root:root . chmod -R u+w,go+r-w,a-s . echo Building ... [ "${OPENGL}" = "YES" ] && do_opengl="" || do_opengl="out" LDFLAGS="-L/usr/lib -ldl" \ CFLAGS="$SLKCFLAGS" \ CXXFLAGS="$SLKCFLAGS" \ ./configure \ --prefix=/usr \ --libdir=/usr/lib \ --localstatedir=/var \ --sysconfdir=/etc \ --mandir=/usr/man \ --with-x \ --with-fontconfig \ --with-freetype \ --without-ldap \ --without-nas \ --with${do_opengl}-opengl \ --program-prefix= \ --program-suffix= \ --build=$ARCH-slamd64-linux \ 2>&1 | tee $OUTPUT/configure-${PRGNAM}.log
make depend 2>&1 | tee $OUTPUT/make-${PRGNAM}.log
make 2>&1 | tee -a $OUTPUT/make-${PRGNAM}.log
make DESTDIR=$PKG install 2>&1 |tee $OUTPUT/install-${PRGNAM}.log

# Add a desktop menu for the winecfg program:
mkdir -p $PKG/usr/share/pixmaps
cp -a programs/winemenubuilder/wine.xpm $PKG/usr/share/pixmaps/
mkdir -p $PKG/usr/share/applications
cat <<-_EOT_ > $PKG/usr/share/applications/winecfg.desktop
[Desktop Entry]
Exec=winecfg
Icon=/usr/share/pixmaps/wine.xpm
Terminal=false
Name=Wine Configuration
Comment=Configure Wine
Type=Application
Categories=Application;Settings
_EOT_

# Add some documentation to the package:
mkdir -p $PKG/usr/doc/$PRGNAM-$VERSION
cp -a $DOCS $PKG/usr/doc/$PRGNAM-$VERSION || true
cp -a $SRCDIR/$(basename $0) $PKG/usr/doc/$PRGNAM-$VERSION/$PRGNAM.SlackBuild
chown -R root:root $PKG/usr/doc/$PRGNAM-$VERSION
find $PKG/usr/doc -type f -exec chmod 644 {} \;


# Compress the man page(s)
if [ -d $PKG/usr/man ]; then
cd $PKG/usr/man
find . -type f -name "*.?" -exec gzip -9f {} \;
for i in $(find . -type l -name "*.?") ; do ln -s $( readlink $i ).gz $i.gz ; rm $i ; done
fi

# Strip binaries
find $PKG | xargs file | grep -e "executable" -e "shared object" \
| grep ELF | cut -f1 -d: | xargs strip --strip-unneeded 2>/dev/null

# Add a package description:
mkdir -p $PKG/install
cat $SRCDIR/slack-desc > $PKG/install/slack-desc
if [ -f $SRCDIR/doinst.sh ]; then
cat $SRCDIR/doinst.sh >> $PKG/install/doinst.sh
fi
if [ -f $SRCDIR/slack-required ]; then
cat $SRCDIR/slack-required > $PKG/install/slack-required
fi

# Build the package:
cd $PKG
makepkg --linkadd y --chown n $OUTPUT/${PRGNAM}-${VERSION}-${ARCH}-${BUILD}${TAG}.tgz 2>&1 | tee $OUTPUT/makepkg-${PRGNAM}.log
cd $OUTPUT
md5sum ${PRGNAM}-${VERSION}-${ARCH}-${BUILD}${TAG}.tgz > ${PRGNAM}-${VERSION}-${ARCH}-${BUILD}${TAG}.tgz.md5
cd -
cat $PKG/install/slack-desc | grep "^${PRGNAM}" > $OUTPUT/${PRGNAM}-${VERSION}-${ARCH}-${BUILD}${TAG}.txt
if [ -f $PKG/install/slack-required ]; then
cat $PKG/install/slack-required > $OUTPUT/${PRGNAM}-${VERSION}-${ARCH}-${BUILD}${TAG}.dep
fi


Note that the Wine that I built is a 32-bit Wine version 1.1.33. Therefore, it must link to the 32-bit compatibility package in my Slamd64. I haven't tested whether this configuration will work flawlessly if the 64-bit libraries is linked to the Wine sources in the package build process. Another thing is I installed Fontforge prior to building the Wine package from its source files.


The Fontforge and Wine packages were installed using installpkg utility. Now let's see the default installation screenshot.






As you can see in the image above, the font rendering is bad for long time viewing, because of the "jagged" font rendering. The strain in the eyes just cannot be neglected anymore. Fortunately, someone posted the way to enable "subpixel font rendering" on the web. I was a bit clueless about accessing the registry at first--you need to access the registry to enable the subpixel font rendering. But, I found that you just need to run winefile from your shell (in X of course) and then go to the Windows directory in drive C:\ in your wine installation. The regedit.exe program is there. Now, let's have a look at the whole steps to enable subpixel font rendering:

  1. First go to your Windows directory in your wine installation.

  2. Run regedit.exe

  3. Go to [HKEY_CURRENT_USER\Control Panel\Desktop] and set the following values (create the new entries if they haven't exist yet):

    • "FontSmoothing"="2"

    • "FontSmoothingType"=dword:00000002

    • "FontSmoothingGamma"=dword:00000578

    • "FontSmoothingOrientation"=dword:0000000



  4. You have to close all applications that use Wine and start them afterwards to see the result


Now, let's see the result. Below are the screenshots of application running in Wine with subpixel font rendering enabled.








I come across this solution after twiddling with various versions of Wine. Some Wine versions older than version 1.1.18 will just crash when I try to change the font in IDA Pro. Even version 1.1.18 will make IDA Pro crash if I linked it with Fontforge. The version which works without crashing is version 1.1.33. But its font is awful without enabling the subpixel font rendering.


Post a Comment

2 comments:

twickline said...

Hello,

I also have a post about wine font fixes on my site and some info on why the fonts render as they do.

see : How to enable font anti-aliasing in Wine

Cheers,
Tom

Darmawan Salihun said...

Hello, thanks for the link :-)