summaryrefslogtreecommitdiff
path: root/src/Font.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/Font.cc')
-rw-r--r--src/Font.cc333
1 files changed, 333 insertions, 0 deletions
diff --git a/src/Font.cc b/src/Font.cc
new file mode 100644
index 00000000..f377c5eb
--- /dev/null
+++ b/src/Font.cc
@@ -0,0 +1,333 @@
+// -*- 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 "i18n.hh"
+#include "Font.hh"
+#include "Util.hh"
+#include "GCCache.hh"
+#include "Color.hh"
+
+//bool BFont::_antialias = False;
+string BFont::_fallback_font = "fixed";
+
+
+BFont::BFont(Display *d, BScreen *screen, const string &family, int size,
+ bool bold, bool italic) : _display(d),
+ _screen(screen),
+ _name(family),
+ _simplename(False),
+ _size(size * 10),
+ _bold(bold),
+ _italic(italic),
+#ifdef XFT
+ _xftfont(0),
+#endif // XFT
+ _font(0),
+ _fontset(0),
+ _fontset_extents(0),
+ _cache(0),
+ _item(0) {
+ _valid = init();
+}
+
+
+BFont::BFont(Display *d, BScreen *screen, const string &xlfd) :
+ _display(d),
+ _screen(screen),
+#ifdef XFT
+ _xftfont(0),
+#endif // XFT
+ _font(0),
+ _fontset(0),
+ _fontset_extents(0),
+ _cache(0),
+ _item(0) {
+ string int_xlfd;
+ if (xlfd.empty())
+ int_xlfd = _fallback_font;
+ else
+ int_xlfd = xlfd;
+
+ _valid = init(xlfd);
+}
+
+
+bool BFont::init(const string &xlfd) {
+ // try load the specified font
+ if (xlfd.empty() || parseFontString(xlfd))
+ if (createFont())
+ return True;
+
+ if (xlfd != _fallback_font) {
+ // try the fallback
+ cerr << "BFont::BFont(): couldn't load font '" << _name << "'" << endl <<
+ "Falling back to default '" << _fallback_font << "'" << endl;
+ if (parseFontString(_fallback_font))
+ if (createFont())
+ return True;
+ }
+
+ cerr << "BFont::BFont(): couldn't load font '" << _name << "'" << endl <<
+ "Giving up!" << endl;
+
+ return False;
+}
+
+
+bool BFont::createFont(void) {
+ std::string fullname;
+
+#ifdef XFT
+ fullname = buildXlfdName(False);
+ _xftfont = XftFontOpenXlfd(_display, _screen->getScreenNumber(),
+ fullname.c_str());
+ if (_xftfont)
+ return True;
+
+ cerr << "BFont::BFont(): couldn't load font '" << _name << "'" << endl <<
+ "as an Xft font, trying as a standard X font." << endl;
+#endif
+
+ if (i18n.multibyte()) {
+ char **missing, *def = "-";
+ int nmissing;
+
+ fullname = buildXlfdName(True);
+ _fontset = XCreateFontSet(_display, fullname.c_str(), &missing, &nmissing,
+ &def);
+ if (nmissing) XFreeStringList(missing);
+ if (_fontset)
+ _fontset_extents = XExtentsOfFontSet(_fontset);
+ else
+ return False;
+
+ assert(_fontset_extents);
+ }
+
+ fullname = buildXlfdName(False);
+ cerr << "loading font '" << fullname.c_str() << "'\n";
+ _font = XLoadQueryFont(_display, fullname.c_str());
+ if (! _font)
+ return False;
+ return True;
+}
+
+
+BFont::~BFont() {
+#ifdef XFT
+ if (_xftfont)
+ XftFontClose(_display, _xftfont);
+#endif // XFT
+
+ if (i18n.multibyte() && _fontset)
+ XFreeFontSet(_display, _fontset);
+ if (_font)
+ XFreeFont(_display, _font);
+
+ if (_item)
+ _cache->release(_item);
+}
+
+
+/*
+ * Takes _name, _size, _bold, _italic, etc and builds them into a full XLFD.
+ */
+string BFont::buildXlfdName(bool mb) const {
+ string weight = _bold ? "bold" : "medium";
+ string slant = _italic ? "i" : "r";
+ string sizestr= _size ? itostring(_size) : "*";
+
+ if (mb)
+ return _name + ',' +
+ "-*-*-" + weight + "-" + slant + "-*-*-" + sizestr +
+ "-*-*-*-*-*-*-*" + ',' +
+ "-*-*-*-*-*-*-" + sizestr + "-*-*-*-*-*-*-*" + ',' +
+ "*";
+ else if (_simplename)
+ return _name;
+ else
+ return "-*-" + _name + "-" + weight + "-" + slant + "-*-*-*-" +
+ sizestr + "-*-*-*-*-*-*";
+}
+
+
+/*
+ * Takes a full X font name and parses it out so we know if we're bold, our
+ * size, etc.
+ */
+bool BFont::parseFontString(const string &xlfd) {
+ if (xlfd.empty() || xlfd[0] != '-') {
+ _name = 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) _name = string(tmp, it); // s[tmp:it]
+ if (i == 3) weight = string(tmp, it);
+ if (i == 4) slant = string(tmp, it);
+ if (i == 8) 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";
+ if (atoi(sizestr.c_str()))
+ _size = atoi(sizestr.c_str());
+ }
+
+ // min/max size restrictions for sanity, but 0 is the font's "default size"
+ if (_size && _size < 30)
+ _size = 30;
+ else if (_size > 970)
+ _size = 970;
+
+ 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);
+
+ 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.color.alpha = 0xff | 0xff << 8; // no transparency in BColor yet
+ c.pixel = color.pixel();
+
+ XftDrawStringUtf8(draw, &c, _xftfont, x, _xftfont->ascent + y,
+ (XftChar8 *) string.c_str(), string.size());
+
+ XftDrawDestroy(draw);
+ return;
+ }
+#endif // XFT
+
+ if (! _cache)
+ _cache = color.display()->gcCache();
+ if (! _item)
+ _item = _cache->find(color, _font, GXcopy, ClipByChildren);
+
+ assert(_cache);
+ assert(_item);
+
+ if (i18n.multibyte())
+ XmbDrawString(_display, d, _fontset, _item->gc(),
+ x, y - _fontset_extents->max_ink_extent.y,
+ string.c_str(), string.size());
+ else
+ XDrawString(_display, d, _item->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;
+ XftTextExtentsUtf8(_display, _xftfont, (XftChar8 *) string.c_str(),
+ string.size(), &info);
+ return info.xOff;
+ }
+#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;
+#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;
+}