PSFont.py :  » Network » Grail-Internet-Browser » grail-0.6 » printing » Python Open Source

Home
Python Open Source
1.3.1.2 Python
2.Ajax
3.Aspect Oriented
4.Blog
5.Build
6.Business Application
7.Chart Report
8.Content Management Systems
9.Cryptographic
10.Database
11.Development
12.Editor
13.Email
14.ERP
15.Game 2D 3D
16.GIS
17.GUI
18.IDE
19.Installer
20.IRC
21.Issue Tracker
22.Language Interface
23.Log
24.Math
25.Media Sound Audio
26.Mobile
27.Network
28.Parser
29.PDF
30.Project Management
31.RSS
32.Search
33.Security
34.Template Engines
35.Test
36.UML
37.USB Serial
38.Web Frameworks
39.Web Server
40.Web Services
41.Web Unit
42.Wiki
43.Windows
44.XML
Python Open Source » Network » Grail Internet Browser 
Grail Internet Browser » grail 0.6 » printing » PSFont.py
"""Access to font metrics and PostScript name mappings.

All access is through the PSFont class.
"""
__version__ = '$Revision: 1.4 $'

import fonts                            # package
import utils


# This dictionary maps PostScript font names to the normal, bold and
# italic suffixes for the font.  Key is the short name describing the
# font, value is a tuple indicating the real name of the font (for
# mapping fonts to other fonts), then the regular, bold, and italic
# suffix modifiers of the font.  Note that if their is no regular name
# modifier, then use the empty string, but if there is a regular name
# modifier, make sure it includes a leading dash.  Other modifiers
# should not include the dash.

fontdefs = {
    'Times':            (None, '-Roman', 'Bold', 'Italic'),
    'Helvetica':        (None, '',       'Bold', 'Oblique'),
    'NewCenturySchlbk': (None, '-Roman', 'Bold', 'Italic'),
    'Courier':          (None, '',       'Bold', 'Oblique'),
    # The code from HTML-PSformat.c says:
    # "This is a nasty trick, I have put Times in place of Lucida,
    # because most printers don't have Lucida font"
    # Hmm...  -BAW
    #'Lucida':           ('Times', None, 'Bold', 'Italic'),
    'Lucida':           (None, '', 'Bold', 'Italic'),
    #
    'Palatino':         (None, '-Roman', 'Bold', 'Italic'),
    }

# Mappings between HTML header tags and font sizes
# Entries in the dictionary are factors used with DEFAULT_FONT_SIZE
# The values used by Mosaic
#DEFAULT_FONT_SIZE = 12.0
#font_sizes = {
#    None: 1.0,
#    'h1': 3.0,
#    'h2': 2.0,
#    'h3': 1.5,
#    'h4': 1.67,
#    'h5': 1.0,
#    'h6': 0.83
#    }

# The values used by Grail
DEFAULT_FONT_SIZE = 10.0
font_sizes = {
    None: 1.0,
    'h1': 1.8,
    'h2': 1.4,
    'h3': 1.2,
    'h4': 1.0,
    'h5': 1.0,
    'h6': 1.0
    }


class PSFont:
    """This class manages font changes and calculation of associated
    metrics for PostScript output.  It basically defines a mapping
    between a PostScript definition for a font and a short name used
    by PostScript functions defined in header.ps.

    When the font is created, it is passed the name of a variable
    width family and a fixed width family.  Those are the only
    configuration options you have.  Should probably allow a scaling
    factor to be passed in, mapping GUI dpi to PostScript dpi, but
    that would have to be calculated by Grail for the underlying GUI.

    Exported methods:

       __init__(optional: VARIFAMILY, FIXEDFAMILY)
       set_font((SIZE, ITALIC?, BOLD?, TT?)) ==> (PSFONTNAME, SIZE)
       text_width(TEXT) ==> WIDTH_IN_POINTS
       font_size(optional: (SIZE, ITALIC?, BOLD?, TT?)) ==> SZ_IN_POINTS
    """
    def __init__(self, varifamily='Times', fixedfamily='Courier',
                 size=DEFAULT_FONT_SIZE):
        """Create a font definition using VARIFAMILY as the variable
        width font and FIXEDFAMILY as the fixed width font.  Defaults
        to Helvetica and Courier respectively.
        """
        # current font is a tuple of size, family, italic, bold
        self.vfamily = varifamily
        self.ffamily = fixedfamily
        self.font = (size, 'FONTV', '', '')
        self.base_size = self._fontsize = size

        # TBD: this number is slightly bogus, but the rational is
        # thus.  The original code was tied fairly closely with X so
        # it had to map screen resolutions to PostScript.  I don't
        # want this version to be tied to X at all, if possible, so I
        # ignore all screen resolution parameters.  The tradeoff is
        # that the hardcopy will probably not be formatted exactly as
        # it appears on the screen, but I believe that is appropriate.
        # Should we decide to change that, this scaling factor may
        # come into play, but should probably be passed in from Grail,
        # since only it can interface to the underlying window system.
        self.points_per_pixel = 72.0 / 72.0

        # calculate document fonts
        if not fontdefs.has_key(self.vfamily): self.vfamily = 'Helvetica'
        if not fontdefs.has_key(self.ffamily): self.ffamily = 'Courier'
        vrealname, vreg, vbold, vitalic = fontdefs[self.vfamily]
        frealname, freg, fbold, fitalic = fontdefs[self.ffamily]
        # fonts may be mapped to other fonts
        if not vrealname: vrealname = self.vfamily
        if not frealname: frealname = self.ffamily

        # calculate font names in PostScript space. Eight fonts are
        # used, naming scheme is as follows.  All PostScript font
        # name definitions start with `FONT', followed by `V' for the
        # variable width font and `F' for the fixed width font.  `B'
        # for the bold version, `I' for italics, and for the
        # bold-italic version, `B' *must* preceed `I'.  See header.ps
        # for more info.
        self.docfonts = {
            'FONTV':   '%s%s' % (vrealname, vreg),
            'FONTVB':  '%s-%s' % (vrealname, vbold),
            'FONTVI':  '%s-%s' % (vrealname, vitalic),
            'FONTVBI': '%s-%s%s' % (vrealname, vbold, vitalic),
            'FONTF':   '%s%s' % (frealname, freg),
            'FONTFB':  '%s-%s' % (frealname, fbold),
            'FONTFI':  '%s-%s' % (frealname, fitalic),
            'FONTFBI': '%s-%s%s' % (frealname, fbold, fitalic)
            }
        # instantiated font objects
        self.fontobjs = {}
        self.tw_func = None

    def get_font(self):
        """Returns the font nickname and size.

        This is the only place the nickname is computed.
        """
        sz, family, italic, bold = self.font
        nick = "%s%s%s" % (family, bold, italic)
##      utils.debug("get_font(): %s ==> %s\n" % (self.font, (nick, sz)))
        return nick, sz

    def set_font(self, font_tuple):
        """Set the current font to that specified by FONT_TUPLE, which
        is of the form (SIZE, ITALIC?, BOLD?, TT?).  Returns the
        PostScript layer name of the font, and the font size in
        points.  """
        # we *said* we wanted a tuple
        if font_tuple is None: font_tuple = (None, None, None, None)
##      utils.debug("set_font(%s)\n" % (font_tuple,))
        set_sz, set_italic, set_bold, set_tt = font_tuple
        # get the current font and break up the tuple
        cur_sz, cur_family, cur_italic, cur_bold = self.font
        # calculate size
        new_sz = self.font_size(font_tuple)
        # calculate variable vs. fixed base name
        if set_tt: new_family = 'FONTF'
        else: new_family = 'FONTV'

        # add modifiers.  Because of the way fonts are named, always
        # add bold modifier before italics modifier, in case both are
        # present
        if set_bold: new_bold = 'B'
        else: new_bold = ''

        if set_italic: new_italic = 'I'
        else: new_italic = ''

        # save the current font specification
        self.font = (new_sz, new_family, new_italic, new_bold)

        # get the font nickname
        fontnickname, new_sz = self.get_font()

        # make sure the font object is instantiated
        if not self.fontobjs.has_key(fontnickname):
            psfontname = self.docfonts[fontnickname]
            self.fontobjs[fontnickname] = fonts.font_from_name(psfontname)
##      print fontnickname, "==>", self.fontobjs[fontnickname]
        self.tw_func = self.fontobjs[fontnickname].text_width

        self._fontsize = new_sz

        # return the PostScript font definition and the size in points
        return (fontnickname, new_sz)

    def text_width(self, text):
##      width = self.tw_func(self._fontsize, text)
##      utils.debug("%s @ %spt ==> %s" % (`text`, self._fontsize, width),
##                  'charsizing')
##      return width
        return self.tw_func(self._fontsize, text)

    def font_size(self, font_tuple=None):
        """Return the size of the current font, or the font defined by
        optional FONT_TUPLE if present."""
        if not font_tuple:
            return self._fontsize
        tuple_sz = font_tuple[0]
        if type(tuple_sz) is type(1.0):
            return tuple_sz
        try:
            return font_sizes[tuple_sz] * self.base_size
        except KeyError:
            return self.base_size
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.