PreviousUpNext

15.4.1624  src/lib/x-kit/xclient/src/window/font-base.pkg

## font-base.pkg
#
# The basic definitions for fonts.
#
#   "Fonts and their related character metrics
#    follow the standard X model.  However in
#    [x-kit] font information is viewed as logically
#    part of the font;  there is no separate font
#    information data structure."
#       -- p18, http://mythryl.org/pub/exene/1993-lib.ps
#         (John Reppy's 1993 eXene library manual.)
#
#
# See also:  some possibly useful code here,
# although it does not currently compile:               XXX BUGGO FIXME
#
#     src/lib/x-kit/widget/old/fancy/2d-graphics/scalable-font.pkg


# Compiled by:
#     src/lib/x-kit/xclient/xclient-internals.sublib






###                "A good stack of examples, as large as possible,
###                 is indispensable for a thorough understanding
###                 of any concept, and when I want to learn something
###                 new, I make it my first job to build one."
###
###                                       Paul Halmos


stipulate
    #
    package xt  =  xtypes;                                                      # xtypes                        is from   src/lib/x-kit/xclient/src/wire/xtypes.pkg
    package sok =  socket__premicrothread;                                      # socket__premicrothread        is from   src/lib/std/socket--premicrothread.pkg
    package dy  =  display;                                                     # display                       is from   src/lib/x-kit/xclient/src/wire/display.pkg
herein


    package font_base {
        #
        exception NO_CHAR_INFO;                                                 # Raised by the char_info functions.

        exception FONT_PROPERTY_NOT_FOUND;

        Font_Info                                                               # For background here see p38 in   http://mythryl.org/pub/exene/X-protocol-R7.pdf
            =
            FINFO8
              {
                min_bounds:       xt::Char_Info,
                max_bounds:       xt::Char_Info,
                #       
                min_char:         Int,
                max_char:         Int,
                #       
                default_char:     Int,
                #       
                draw_dir:         xt::Font_Drawing_Direction,
                all_chars_exist:  Bool,
                #       
                font_ascent:      Int,
                font_descent:     Int,
                #       
                properties:       List( xt::Font_Prop ),
                char_info:        Int -> xt::Char_Info
              }

          | FINFO16
              {
                min_bounds:       xt::Char_Info,
                max_bounds:       xt::Char_Info,
                #       
                min_char:         Int,
                max_char:         Int,
                #       
                default_char:     Int,
                #       
                draw_dir:         xt::Font_Drawing_Direction,
                all_chars_exist:  Bool,
                #       
                min_byte1:        Int,
                max_byte1:        Int,
                #       
                font_ascent:      Int,
                font_descent:     Int,
                #       
                properties:       List(  xt::Font_Prop ),
                char_info:        Int -> xt::Char_Info
              };

        Font =  { id:    xt::Font_Id,
                  xdpy:  dy::Xdisplay,          # Display to which this font belongs.
                  info:  Font_Info
                };

        # Identity test:
        #
        fun same_font (
              { id=>id1, xdpy=> { socket => c1, ... }: dy::Xdisplay, ... }: Font,
              { id=>id2, xdpy=> { socket => c2, ... }: dy::Xdisplay, ... }: Font
            )
           =
           xt::same_xid (id1, id2)
           and
#           xok::same_xsocket (c1, c2);
           c1 == c2;

        # Find a given property of a font:
        #
        fun font_property_of ({ info, ... }: Font) atom
            =
            get properties
            where 
                #
                properties
                    =
                    case info
                        #
                        FINFO8  { properties, ... } =>   properties;
                        FINFO16 { properties, ... } =>   properties;
                    esac;

                fun get [] =>   raise exception FONT_PROPERTY_NOT_FOUND;
                    #
                    get ((xt::FONT_PROP { name, value } ) ! r)
                        =>
                        name == atom  ??  value
                                      ::  get  r;
                end;

            end;

        # Return the non-character specific info for the font 
        #
        fun font_info_of ({ info=>(FINFO8 x), ... }: Font)
                =>
                {   min_bounds => x.min_bounds,
                    max_bounds => x.max_bounds,

                    min_char => x.min_char,
                    max_char => x.max_char
                };

            font_info_of ({ info=>(FINFO16 x), ... }: Font)
                =>
                {   min_bounds => x.min_bounds,
                    max_bounds => x.max_bounds,

                    min_char => x.min_char,
                    max_char => x.max_char
                };
        end;

        # Return the character info about
        # a given character in a given font.
        #
        # The character is specified as an ordinal.
        # We raise the exception NO_CHAR_INFO if
        # the given ordinal does not correspond
        # to a character in the font.
        #
        fun char_info_of ({ info, ... }: Font)
            =
            case info
                #
                FINFO8  { char_info, ... } =>   char_info;
                FINFO16 { char_info, ... } =>   char_info;
            esac;

        # Return the width in pixels of
        # a given character in a given font.
        #
        fun char_width font
            =
            width_fn
            where 
                info_of = char_info_of font;
                #
                fun width_fn c
                    =
                    {   (info_of (char::to_int c))
                            ->
                            xt::CHAR_INFO { char_width, ... };

                        char_width;
                    }
                    except _ = 0;
            end;

        # Return the width in pixels of
        # a string in the given font.
        #
        fun text_width font
            =
            width_fn
            where 
                char_width_fn =  char_width  font;
                #
                fun width_fn s
                    =
                    width_fn' (0, 0)
                    where
                        len = string::length_in_bytes s;
                        #
                        fun width_fn' (width, i)
                            =
                            if (i < len)    width_fn' (width + char_width_fn (string::get_byte_as_char (s, i)), i+1);
                            else            width;
                            fi;
                    end;

            end;

        # Return the width of the substring s[i..i+n - 1] in the given font 
        #
        fun substr_width font
            =
            width_fn
            where 
                char_width_fn =   char_width  font;
                #
                fun width_fn (s, i, n)
                    =
                    width_fn' (0, i)
                    where 
                        len =   int::min (size s, i+n);
                        #
                        fun width_fn' (width, i)
                            =
                            if (i < len)    width_fn' (width + char_width_fn (string::get_byte_as_char (s, i)), i+1);
                            else            width;
                            fi;
                    end;

              end;

        # Return a list containing the pixel position
        # of each character in given string, in given font.
        #
        # In other words, return a list containing the
        # width in pixels of each non-empty prefix of
        # the string, in the given font.
        #
        # For a string of length n, this returns a list of length n+1.
        #
        fun char_positions font
            =
            {   char_width_fn =   char_width  font;
                #
                fun positions s
                    =
                    width_fn ([0], 0, 0)
                    where 
                        len = string::length_in_bytes s;
                        #
                        fun width_fn (l, width, i)
                            =
                            if (i < len)
                                #
                                wide =   width + char_width_fn (string::get_byte_as_char (s, i));

                                width_fn (wide ! l, wide, i + 1);
                            else
                                reverse l;
                            fi;
                      end;

                  positions;
              };

        # Return the extents of the given string in the given font, which is a record
        # with the fields
        #     dir:          font_draw_dir,
        #     font_ascent:  Int,
        #     font_descent:  Int,
        #     overall_info:  char_info
        # The dir, font_ascent and font_descent fields give the font properties.  The
        # overall_info field describes the bounding box of the string if written at
        # the origin. The upper left corner of the bounding box is at
        #    (left_bearing, -ascent)
        # the dimensions of the bounding box are
        #    (right_bearing - left_bearing, ascent + descent).
        # The width is the sum of the widths of all the characters in the string. 
        #
        fun text_extents ({ info, ... }: Font) s
            =
            {
                my (info_of, dir, font_ascent, font_descent)
                    =
                    case info
                        #
                        FINFO8 { char_info, draw_dir, font_ascent, font_descent, ... }
                            =>
                            (char_info, draw_dir, font_ascent, font_descent);

                        FINFO16 { char_info, draw_dir, font_ascent, font_descent, ... }
                            =>
                            (char_info, draw_dir, font_ascent, font_descent);
                    esac;

                len = string::length_in_bytes s;

                fun min (a:  Int, b) =  (a < b)  ??  a  ::  b;
                fun max (a:  Int, b) =  (a > b)  ??  a  ::  b;

                fun ord_of   i =  string::get_byte (s, i);
                fun get_info i =  (THE (info_of (ord_of i))) except _ = NULL;

                fun accum_none i
                    =
                    if (i < len)
                        #
                        case (get_info i)
                            #
                            NULL => accum_none (i+1);

                            THE (xt::CHAR_INFO info)
                                =>
                                accum (
                                    { ascent  =>   info.ascent,
                                      descent =>   info.descent,
                                      lbear   =>   info.left_bearing,
                                      rbear   =>   info.right_bearing,
                                      width   =>   info.char_width
                                    },

                                    i + 1
                                );
                         esac;
                    else
                        { ascent  => 0,
                          descent => 0,
                          lbear   => 0,
                          rbear   => 0,
                          width   => 0
                        };
                    fi

                also
                fun accum (arg as { ascent, descent, lbear, rbear, width }, i)
                    =
                    if (i < len)
                        #
                        case (get_info i)
                            #
                            NULL => accum (arg, i+1);

                            THE (xt::CHAR_INFO info)
                                =>
                                accum(
                                    { ascent  => max (ascent, info.ascent),
                                      descent => max (descent, info.descent),
                                      lbear   => min (lbear, width + info.left_bearing),
                                      rbear   => max (rbear, width + info.right_bearing),
                                      width   => width + info.char_width
                                    },

                                    i + 1
                                );
                        esac;
                    else
                        arg;
                    fi;

                (accum_none 0)
                    ->
                    { ascent, descent, lbear, rbear, width };

                { dir,
                  font_ascent,
                  font_descent,
                  #
                  overall_info
                      =>
                      xt::CHAR_INFO
                        {
                          ascent,
                          descent,
                          char_width    => width,
                          left_bearing  => lbear,
                          right_bearing => rbear,
                          attributes    => 0u0
                        }
                };
            };

        fun font_high ({ info=>FINFO8 { font_ascent, font_descent, ... }, ... }: Font)
                =>
                { ascent  => font_ascent,
                  descent => font_descent
                };

            font_high ({ info=>FINFO16 { font_ascent, font_descent, ... }, ... }: Font)
                =>
                { ascent  => font_ascent,
                  descent => font_descent
                };
        end;

    };          # package font_base 
end;            # stipulate


Comments and suggestions to: bugs@mythryl.org

PreviousUpNext