summaryrefslogtreecommitdiff
path: root/src/font.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/font.cc')
-rw-r--r--src/font.cc374
1 files changed, 374 insertions, 0 deletions
diff --git a/src/font.cc b/src/font.cc
new file mode 100644
index 00000000..ba1ae1c1
--- /dev/null
+++ b/src/font.cc
@@ -0,0 +1,374 @@
+// -*- mode: C++; indent-tabs-mode: nil; c-basic-offset: 2; -*-
+// Font.cc for Blackbox - an X11 Window manager
+// Copyright (c) 2001 - 2002 Sean 'Shaleh' Perry <shaleh@debian.org>
+// Copyright (c) 1997 - 2000 Brad Hughes (bhughes@tcac.net)
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the "Software"),
+// to deal in the Software without restriction, including without limitation
+// the rights to use, copy, modify, merge, publish, distribute, sublicense,
+// and/or sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+
+#ifdef HAVE_CONFIG_H
+# include "../config.h"
+#endif // HAVE_CONFIG_H
+
+extern "C" {
+#ifdef HAVE_STDLIB_H
+# include <stdlib.h>
+#endif // HAVE_STDLIB_H
+}
+
+#include <iostream>
+#include <algorithm>
+
+using std::string;
+using std::cerr;
+using std::endl;
+
+#include "font.hh"
+#include "util.hh"
+#include "gccache.hh"
+#include "color.hh"
+
+string BFont::_fallback_font = "fixed";
+
+#ifdef XFT
+BFont::BFont(Display *d, BScreen *screen, const string &family, int size,
+ bool bold, bool italic, bool shadow, unsigned char offset,
+ unsigned char tint, bool antialias) :
+ _display(d),
+ _screen(screen),
+ _family(family),
+ _simplename(False),
+ _size(size),
+ _bold(bold),
+ _italic(italic),
+ _antialias(antialias),
+ _shadow(shadow),
+ _offset(offset),
+ _tint(tint),
+ _xftfont(0),
+ _font(0),
+ _fontset(0),
+ _fontset_extents(0) {
+ _valid = False;
+
+ _xftfont = XftFontOpen(_display, _screen->getScreenNumber(),
+ XFT_FAMILY, XftTypeString, _family.c_str(),
+ XFT_SIZE, XftTypeInteger, _size,
+ XFT_WEIGHT, XftTypeInteger, (_bold ?
+ XFT_WEIGHT_BOLD :
+ XFT_WEIGHT_MEDIUM),
+ XFT_SLANT, XftTypeInteger, (_italic ?
+ XFT_SLANT_ITALIC :
+ XFT_SLANT_ROMAN),
+ XFT_ANTIALIAS, XftTypeBool, _antialias,
+ 0);
+ if (! _xftfont)
+ return; // failure
+
+ _font = XLoadQueryFont(_display, buildXlfd().c_str());
+ if (! _font)
+ return; // failure
+
+ _valid = True;
+}
+#endif
+
+
+BFont::BFont(Display *d, BScreen *screen, const string &xlfd) :
+ _display(d),
+ _screen(screen),
+#ifdef XFT
+ _antialias(False),
+ _shadow(False),
+ _xftfont(0),
+#endif // XFT
+ _font(0),
+ _fontset(0),
+ _fontset_extents(0) {
+ string int_xlfd;
+ if (xlfd.empty())
+ int_xlfd = _fallback_font;
+ else
+ int_xlfd = xlfd;
+
+ if ((_valid = createXFont(int_xlfd)))
+ return; // success
+
+ if (int_xlfd != _fallback_font) {
+ // try the fallback
+ cerr << "BFont::BFont(): couldn't load font '" << _family << "'" << endl <<
+ "Falling back to default '" << _fallback_font << "'" << endl;
+
+ if ((_valid = createXFont(_fallback_font)))
+ return; // success
+ }
+
+ cerr << "BFont::BFont(): couldn't load font '" << _family << "'" << endl <<
+ "Giving up!" << endl;
+ return; // failure
+}
+
+
+bool BFont::createXFont(const std::string &xlfd) {
+ /*
+ Even though this is only used for font sets (multibyte), it is still parsed
+ out so that the bold/italic/etc information is still available from the
+ class when using non-multibyte.
+
+ This is where _simplename, _bold, _italic, and _size are initialized, since
+ they are not initialized in the constructor. This needs to occur before
+ calling any Xlfd-building functions.
+ */
+ if (! parseXlfd(xlfd))
+ return False;
+
+ if (i18n.multibyte()) {
+ char **missing, *def = "-";
+ int nmissing;
+
+ _fontset = XCreateFontSet(_display, buildMultibyteXlfd().c_str(),
+ &missing, &nmissing, &def);
+ if (nmissing) XFreeStringList(missing);
+ if (_fontset)
+ _fontset_extents = XExtentsOfFontSet(_fontset);
+ else
+ return False;
+
+ assert(_fontset_extents);
+ }
+
+ _font = XLoadQueryFont(_display, xlfd.c_str());
+ if (! _font)
+ return False;
+ return True;
+}
+
+
+BFont::~BFont(void) {
+#ifdef XFT
+ if (_xftfont)
+ XftFontClose(_display, _xftfont);
+#endif // XFT
+
+ if (i18n.multibyte() && _fontset)
+ XFreeFontSet(_display, _fontset);
+ if (_font)
+ XFreeFont(_display, _font);
+}
+
+
+/*
+ * Takes _family, _size, _bold, _italic, etc and builds them into a full XLFD.
+ */
+string BFont::buildXlfd(void) const {
+ if (_simplename)
+ return _family;
+
+ string weight = _bold ? "bold" : "medium";
+ string slant = _italic ? "i" : "r";
+ string sizestr= _size ? itostring(_size * 10) : "*";
+
+ return "-*-" + _family + "-" + weight + "-" + slant + "-*-*-*-" + sizestr +
+ "-*-*-*-*-*-*";
+}
+
+
+/*
+ * Takes _family, _size, _bold, _italic, etc and builds them into a full XLFD.
+ */
+string BFont::buildMultibyteXlfd(void) const {
+ string weight = _bold ? "bold" : "medium";
+ string slant = _italic ? "i" : "r";
+ string sizestr= _size ? itostring(_size) : "*";
+
+ return _family + ','
+ + "-*-*-" + weight + "-" + slant + "-*-*-*-" + sizestr +
+ "-*-*-*-*-*-*" + ','
+ + "-*-*-*-*-*-*-*-" + sizestr + "-*-*-*-*-*-*" + ',' +
+ + "*";
+}
+
+
+/*
+ * Takes a full X font name and parses it out so we know if we're bold, our
+ * size, etc.
+ */
+bool BFont::parseXlfd(const string &xlfd) {
+ if (xlfd.empty() || xlfd[0] != '-') {
+ _family = xlfd;
+ _simplename = True;
+ _bold = False;
+ _italic = False;
+ _size = 0;
+ } else {
+ _simplename = False;
+ string weight,
+ slant,
+ sizestr;
+ int i = 0;
+
+ string::const_iterator it = xlfd.begin(), end = xlfd.end();
+ while(1) {
+ string::const_iterator tmp = it; // current string.begin()
+ it = std::find(tmp, end, '-'); // look for comma between tmp and end
+ if (i == 2) _family = string(tmp, it); // s[tmp:it]
+ if (i == 3) weight = string(tmp, it);
+ if (i == 4) slant = string(tmp, it);
+ if (i == 7 && string(tmp, it) != "*") sizestr = string(tmp, it);
+ if (sizestr.empty() &&
+ i == 8 && string(tmp, it) != "*") sizestr = string(tmp, it);
+ if (it == end || i >= 8)
+ break;
+ ++it;
+ ++i;
+ }
+ if (i < 3) // no name even! can't parse that
+ return False;
+ _bold = weight == "bold" || weight == "demibold";
+ _italic = slant == "i" || slant == "o";
+ _size = atoi(sizestr.c_str()) / 10;
+ }
+
+ // min/max size restrictions for sanity, but 0 is the font's "default size"
+ if (_size && _size < 3)
+ _size = 3;
+ else if (_size > 97)
+ _size = 97;
+
+ return True;
+}
+
+
+void BFont::drawString(Drawable d, int x, int y, const BColor &color,
+ const string &string) const {
+ assert(_valid);
+
+#ifdef XFT
+ if (_xftfont) {
+ XftDraw *draw = XftDrawCreate(_display, d, _screen->getVisual(),
+ _screen->getColormap());
+ assert(draw);
+
+ if (_shadow) {
+ XftColor c;
+ c.color.red = 0;
+ c.color.green = 0;
+ c.color.blue = 0;
+ c.color.alpha = _tint | _tint << 8; // transparent shadow
+ c.pixel = BlackPixel(_display, _screen->getScreenNumber());
+
+#ifdef XFT_UTF8
+ XftDrawStringUtf8(
+#else
+ XftDrawString8(
+#endif
+ draw, &c, _xftfont, x + _offset,
+ _xftfont->ascent + y + _offset, (XftChar8 *) string.c_str(),
+ string.size());
+ }
+
+ XftColor c;
+ c.color.red = color.red() | color.red() << 8;
+ c.color.green = color.green() | color.green() << 8;
+ c.color.blue = color.blue() | color.blue() << 8;
+ c.pixel = color.pixel();
+ c.color.alpha = 0xff | 0xff << 8; // no transparency in BColor yet
+
+#ifdef XFT_UTF8
+ XftDrawStringUtf8(
+#else
+ XftDrawString8(
+#endif
+ draw, &c, _xftfont, x, _xftfont->ascent + y,
+ (XftChar8 *) string.c_str(), string.size());
+
+ XftDrawDestroy(draw);
+ return;
+ }
+#endif // XFT
+
+ BPen pen(color, _font);
+
+ if (i18n.multibyte())
+ XmbDrawString(_display, d, _fontset, pen.gc(),
+ x, y - _fontset_extents->max_ink_extent.y,
+ string.c_str(), string.size());
+ else
+ XDrawString(_display, d, pen.gc(),
+ x, _font->ascent + y,
+ string.c_str(), string.size());
+}
+
+
+unsigned int BFont::measureString(const string &string) const {
+ assert(_valid);
+
+#ifdef XFT
+ if (_xftfont) {
+ XGlyphInfo info;
+
+#ifdef XFT_UTF8
+ XftTextExtentsUtf8(
+#else
+ XftTextExtents8(
+#endif
+ _display, _xftfont, (XftChar8 *) string.c_str(),
+ string.size(), &info);
+
+ return info.xOff + (_shadow ? _offset : 0);
+ }
+#endif // XFT
+
+ if (i18n.multibyte()) {
+ XRectangle ink, logical;
+ XmbTextExtents(_fontset, string.c_str(), string.size(), &ink, &logical);
+ return logical.width;
+ } else {
+ return XTextWidth(_font, string.c_str(), string.size());
+ }
+}
+
+
+unsigned int BFont::height(void) const {
+ assert(_valid);
+
+#ifdef XFT
+ if (_xftfont)
+ return _xftfont->height + (_shadow ? _offset : 0);
+#endif // XFT
+
+ if (i18n.multibyte())
+ return _fontset_extents->max_ink_extent.height;
+ else
+ return _font->ascent + _font->descent;
+}
+
+
+unsigned int BFont::maxCharWidth(void) const {
+ assert(_valid);
+
+#ifdef XFT
+ if (_xftfont)
+ return _xftfont->max_advance_width;
+#endif // XFT
+
+ if (i18n.multibyte())
+ return _fontset_extents->max_logical_extent.width;
+ else
+ return _font->max_bounds.rbearing - _font->min_bounds.lbearing;
+}