diff options
Diffstat (limited to 'src/libs/graphics/font.c')
-rw-r--r-- | src/libs/graphics/font.c | 334 |
1 files changed, 334 insertions, 0 deletions
diff --git a/src/libs/graphics/font.c b/src/libs/graphics/font.c new file mode 100644 index 0000000..638c814 --- /dev/null +++ b/src/libs/graphics/font.c @@ -0,0 +1,334 @@ +//Copyright Paul Reiche, Fred Ford. 1992-2002 + +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include "gfxintrn.h" +#include "tfb_prim.h" +#include "libs/log.h" + +static inline TFB_Char *getCharFrame (FONT_DESC *fontPtr, UniChar ch); + + +FONT +SetContextFont (FONT Font) +{ + FONT LastFont; + + LastFont = _CurFontPtr; + _CurFontPtr = Font; + if (ContextActive ()) + SwitchContextFont (Font); + + return (LastFont); +} + +BOOLEAN +DestroyFont (FONT FontRef) +{ + if (FontRef == NULL) + return (FALSE); + + if (_CurFontPtr && _CurFontPtr == FontRef) + SetContextFont ((FONT)NULL); + + return (FreeFont (FontRef)); +} + +// XXX: Should be in frame.c (renamed to something decent?) +void +font_DrawText (TEXT *lpText) +{ + RECT ClipRect; + POINT origin; + TEXT text; + + FixContextFontEffect (); + if (!GraphicsSystemActive () || !GetContextValidRect (NULL, &origin)) + return; + + // TextRect() clobbers TEXT.CharCount so we have to make a copy + text = *lpText; + if (!TextRect (&text, &ClipRect, NULL)) + return; + // ClipRect is relative to origin + _text_blt (&ClipRect, &text, origin); +} + +/* Draw the stroke by drawing the same text in the + * background color one pixel shifted to all 4 directions. + */ +void +font_DrawTracedText (TEXT *pText, Color text, Color trace) +{ + // Preserve current foreground color for full correctness + Color oldfg = SetContextForeGroundColor (trace); + pText->baseline.x--; + font_DrawText (pText); + pText->baseline.x += 2; + font_DrawText (pText); + pText->baseline.x--; + pText->baseline.y--; + font_DrawText (pText); + pText->baseline.y += 2; + font_DrawText (pText); + pText->baseline.y--; + SetContextForeGroundColor (text); + font_DrawText (pText); + SetContextForeGroundColor (oldfg); +} + +BOOLEAN +GetContextFontLeading (SIZE *pheight) +{ + if (_CurFontPtr != 0) + { + *pheight = (SIZE)_CurFontPtr->Leading; + return (TRUE); + } + + *pheight = 0; + return (FALSE); +} + +BOOLEAN +GetContextFontLeadingWidth (SIZE *pwidth) +{ + if (_CurFontPtr != 0) + { + *pwidth = (SIZE)_CurFontPtr->LeadingWidth; + return (TRUE); + } + + *pwidth = 0; + return (FALSE); +} + +BOOLEAN +TextRect (TEXT *lpText, RECT *pRect, BYTE *pdelta) +{ + BYTE char_delta_array[MAX_DELTAS]; + FONT FontPtr; + + FontPtr = _CurFontPtr; + if (FontPtr != 0 && lpText->CharCount != 0) + { + COORD top_y, bot_y; + SIZE width; + UniChar next_ch = 0; + const char *pStr; + COUNT num_chars; + + num_chars = lpText->CharCount; + /* At this point lpText->CharCount contains the *maximum* number of + * characters that lpText->pStr may contain. + * After the while loop below, it will contain the actual number. + */ + if (pdelta == 0) + { + pdelta = char_delta_array; + if (num_chars > MAX_DELTAS) + { + num_chars = MAX_DELTAS; + lpText->CharCount = MAX_DELTAS; + } + } + + top_y = 0; + bot_y = 0; + width = 0; + pStr = lpText->pStr; + if (num_chars > 0) + { + next_ch = getCharFromString (&pStr); + if (next_ch == '\0') + num_chars = 0; + } + while (num_chars--) + { + UniChar ch; + SIZE last_width; + TFB_Char *charFrame; + + last_width = width; + + ch = next_ch; + if (num_chars > 0) + { + next_ch = getCharFromString (&pStr); + if (next_ch == '\0') + { + lpText->CharCount -= num_chars; + num_chars = 0; + } + } + + charFrame = getCharFrame (FontPtr, ch); + if (charFrame != NULL && charFrame->disp.width) + { + COORD y; + + y = -charFrame->HotSpot.y; + if (y < top_y) + top_y = y; + y += charFrame->disp.height; + if (y > bot_y) + bot_y = y; + + width += charFrame->disp.width; +#if 0 + if (num_chars && next_ch < (UNICODE) MAX_CHARS + && !(FontPtr->KernTab[ch] + & (FontPtr->KernTab[next_ch] >> 2))) + width -= FontPtr->KernAmount; +#endif + } + + *pdelta++ = (BYTE)(width - last_width); + } + + if (width > 0 && (bot_y -= top_y) > 0) + { + /* subtract off default character spacing */ + if (pdelta[-1] > 0) + { + --pdelta[-1]; + --width; + } + + if (lpText->align == ALIGN_LEFT) + pRect->corner.x = 0; + else if (lpText->align == ALIGN_CENTER) + pRect->corner.x = -(width >> 1); + else + pRect->corner.x = -width; + pRect->corner.y = top_y; + pRect->extent.width = width; + pRect->extent.height = bot_y; + + pRect->corner.x += lpText->baseline.x; + pRect->corner.y += lpText->baseline.y; + + return (TRUE); + } + } + + pRect->corner = lpText->baseline; + pRect->extent.width = 0; + pRect->extent.height = 0; + + return (FALSE); +} + +void +_text_blt (RECT *pClipRect, TEXT *TextPtr, POINT ctxOrigin) +{ + FONT FontPtr; + COUNT num_chars; + UniChar next_ch; + const char *pStr; + POINT origin; + TFB_Image *backing; + DrawMode mode = _get_context_draw_mode (); + + FontPtr = _CurFontPtr; + if (FontPtr == NULL) + return; + backing = _get_context_font_backing (); + if (!backing) + return; + + origin.x = pClipRect->corner.x; + origin.y = TextPtr->baseline.y; + num_chars = TextPtr->CharCount; + if (num_chars == 0) + return; + + pStr = TextPtr->pStr; + + next_ch = getCharFromString (&pStr); + if (next_ch == '\0') + num_chars = 0; + while (num_chars--) + { + UniChar ch; + TFB_Char* fontChar; + + ch = next_ch; + if (num_chars > 0) + { + next_ch = getCharFromString (&pStr); + if (next_ch == '\0') + num_chars = 0; + } + + fontChar = getCharFrame (FontPtr, ch); + if (fontChar != NULL && fontChar->disp.width) + { + RECT r; + + r.corner.x = origin.x - fontChar->HotSpot.x; + r.corner.y = origin.y - fontChar->HotSpot.y; + r.extent.width = fontChar->disp.width; + r.extent.height = fontChar->disp.height; + if (BoxIntersect (&r, pClipRect, &r)) + { + TFB_Prim_FontChar (origin, fontChar, backing, mode, + ctxOrigin); + } + + origin.x += fontChar->disp.width; +#if 0 + if (num_chars && next_ch < (UNICODE) MAX_CHARS + && !(FontPtr->KernTab[ch] + & (FontPtr->KernTab[next_ch] >> 2))) + origin.x -= FontPtr->KernAmount; +#endif + } + } +} + +static inline TFB_Char * +getCharFrame (FONT_DESC *fontPtr, UniChar ch) +{ + UniChar pageStart = ch & CHARACTER_PAGE_MASK; + size_t charIndex; + + FONT_PAGE *page = fontPtr->fontPages; + for (;;) + { + if (page == NULL) + return NULL; + + if (page->pageStart == pageStart) + break; + + page = page->next; + } + + charIndex = ch - page->firstChar; + if (ch >= page->firstChar && charIndex < page->numChars + && page->charDesc[charIndex].data) + { + return &page->charDesc[charIndex]; + } + else + { + //log_add (log_Debug, "Character %u not present", (unsigned int) ch); + return NULL; + } +} + |