TextAsset::Size TextAsset::computeSizeOfText(cairo_t* cairoContext, const std::string textString, int bounds, PangoFontDescription* font, Rect* tight, float* lineHeightOut) { PangoLayout* layout = pango_cairo_create_layout(cairoContext); // Kerning PangoAttrList* attr_list = pango_attr_list_new(); PangoAttribute* spacing_attr = pango_attr_letter_spacing_new(pango_units_from_double(_kern)); pango_attr_list_insert(attr_list, spacing_attr); pango_layout_set_attributes(layout, attr_list); pango_cairo_context_set_resolution(pango_layout_get_context(layout), DISPLAY_RESOLUTION); pango_layout_set_text(layout, textString.c_str(), (int)textString.length()); pango_layout_set_alignment(layout, _alignment); pango_layout_set_wrap(layout, PANGO_WRAP_WORD_CHAR); const Size maxTextureSize(bounds, 1024); pango_layout_set_width(layout, pango_units_from_double(maxTextureSize.width)); pango_layout_set_height(layout, pango_units_from_double(maxTextureSize.height)); pango_layout_set_font_description(layout, font); applyLeading(cairoContext, layout, font); PangoRectangle estimateSize; PangoRectangle ink; pango_layout_get_pixel_extents(layout, &ink, &estimateSize); // If the text is right or center aligned the offsets will contain all the // leading space. We ignore that for the size because drawText will draw // in the larger box. The tight box below will get the offsets so we know // where to draw so the text lands in the same tight box. Size res(estimateSize.width, estimateSize.height); if (tight != NULL) { float lineHeight; float xHeight = charHeight(cairoContext, font, 'x', &lineHeight); if (lineHeightOut != NULL) { *lineHeightOut = lineHeight; } const float capHeight = charHeight(cairoContext, font, 'Y'); const float ascender = pango_units_to_double(pango_layout_get_baseline(layout)); const float topSpace = ascender - capHeight; const float bottomSpace = MAX(lineHeight - ascender - (capHeight - xHeight), 0); if (res.height > topSpace + bottomSpace) { *tight = Rect(estimateSize.x, estimateSize.y + topSpace, res.width, res.height - topSpace - bottomSpace); } else { *tight = Rect(0, 0, res.width, res.height); } } g_object_unref(layout); return res; }
QSize FastoHexEdit::fullSize() const { const int charW = charWidth(); const int charH = charHeight(); const QRect rect = stableRect(viewport()->rect()); const int yPosStart = rect.top(); const int xPosStart = rect.left(); const int yPosEnd = rect.bottom(); const int xPosEnd = rect.right(); const int wid = xPosEnd - xPosStart; const int widchars = wid - TextMarginXY * 2; const int xPosAscii = widchars/4 * 3; // line pos int acharInLine = asciiCharInLine(widchars); int width = xPosAscii + (acharInLine * charW); int height = data_.size() / acharInLine; if (data_.size() % acharInLine) { height++; } height *= charH; return QSize(width, height); }
void acBitmapFont::drawChar(unsigned char c, float x, float y) { // x,y is insertion point, lower-left, on baseline //if (c < 33) return; //if (c > numChars + 32) return; if (!charExists(c)) return; /* if (!charExists(c)) { int m = win2mac[c-128]; if (m == -1) m = 'X'; printf("%d does not exist %c '%c'\n", c, c, m); return; } //if (c+33 > 127) { if (c > 127) { //printf("got something outside: %d\n", c+33); c = win2mac[c]; if (c == -1) return; // char not in encoding printf("found %c\n", (unsigned char)c); } //glEnable(GL_TEXTURE_2D); */ float height = charHeight(c); //float width = charWidth(c); float bwidth = charBitmapWidth(c); float top = charTop(c); float lextent = charLeftExtent(c); #ifndef CANNOT_BIND_TEXTURES if (glIsTexture(texNames[win2mac[c]-33])) { acuNamedTexRectf(x+lextent, y+top, x+lextent+bwidth, y+height+top, texNames[win2mac[c]-33], bwidth, height); } else { sprintf(acuDebugStr, "Could not bind: %c %d\n", c, c); acuDebugString(ACU_DEBUG_MUMBLE); acuTexRectf(x+lextent, y+top, x+lextent+bwidth, y+height+top, images[c-33], GL_RGBA, 4, 64, 64, bwidth, height); } #else acuTexRectf(x+lextent, y+top, x+lextent+bwidth, y+height+top, images[win2mac[c]-33], GL_RGBA, 4, 64, 64, bwidth, height); #endif #if 0 // to draw the baseline glBegin(GL_LINES); glVertex3f(x, y, 0); glVertex3f(x+width*0.95f, y, 0); glEnd(); #endif }
void TextAsset::applyLeading(cairo_t* cairoContext, PangoLayout* layout, PangoFontDescription* font) const { float lineHeight; charHeight(cairoContext, font, 'a', &lineHeight); const float lineSpacing = (_leadingMultiplier - 1.0) * lineHeight; pango_layout_set_spacing(layout, pango_units_from_double(lineSpacing)); }
int Fonts::stringHeight(const Common::String &str) { int height = 0; if (!_font) return 0; for (const char *c = str.c_str(); *c; ++c) height = MAX(height, charHeight(*c)); return height; }
unsigned char* acBitmapFont::getCharData(unsigned char c, float *x, float *y, float *w, float *h) { if (!charExists(c)) return NULL; *x = charLeftExtent(c); *y = charTop(c); *w = charBitmapWidth(c); *h = charHeight(c); /* params[0] = charLeftExtent(c); // x params[1] = charTop(c); // y params[2] = charBitmapWidth(c); // width params[3] = charHeight(c); // height //params[4] = bwidth; // maxu //params[5] = height; // maxv */ return images[c-33]; }
int FastoHexEdit::positionAtPoint(const QPoint &point) const { const int px = point.x(); const int py = point.y(); const int charW = charWidth(); const int charH = charHeight(); const QRect rect = stableRect(viewport()->rect()); const int yPosStart = rect.top(); const int xPosStart = rect.left(); const int yPosEnd = rect.bottom(); const int xPosEnd = rect.right(); const int wid = xPosEnd - xPosStart; const int widchars = wid - TextMarginXY * 2; const int xPosAscii = widchars/4 * 3; //line pos int acharInLine = asciiCharInLine(widchars); if(acharInLine < 0){ acharInLine = 0; } if ((px >= xPosStart && px < xPosAscii) && (py >= yPosStart && py < yPosEnd)){ int posx = (xPosStart + px) / charW; int div = posx / 3; int mod = posx % 3; int pos = 0; //symbol pos in data; if(mod == 0){ pos = div * 2; } else{ pos = (div * 2) + 1; } int firstLineIdx = verticalScrollBar()->value(); int posy = (py - yPosStart) / charH; pos = pos + (firstLineIdx + posy) * acharInLine * 2; return pos; } return -1; }
void FastoHexEdit::paintEvent(QPaintEvent *event) { if (mode_ == HEX_MODE) { QPainter painter(viewport()); QSize areaSize = viewport()->size(); QSize widgetSize = fullSize(); const int charW = charWidth(); const int charH = charHeight(); int firstLineIdx = verticalScrollBar()->value(); int lastLineIdx = firstLineIdx + areaSize.height() / charH; const QRect rect = stableRect(event->rect()); const int yPosStart = rect.top(); const int xPosStart = rect.left(); const int yPosEnd = rect.bottom(); const int xPosEnd = rect.right(); const int wid = xPosEnd - xPosStart; const int height = yPosEnd - yPosStart; const int widchars = wid - TextMarginXY * 2; const int acharInLine = asciiCharInLine(widchars); if (acharInLine <= 0) { return; } const int xPosAscii = widchars/4 * 3; // line pos const int xPosAsciiStart = xPosAscii + TextMarginXY; int indexCount = data_.size() / acharInLine; if (lastLineIdx > indexCount) { lastLineIdx = indexCount; if (data_.size() % acharInLine) { lastLineIdx++; } } verticalScrollBar()->setPageStep(areaSize.height() / charH); verticalScrollBar()->setRange(0, (widgetSize.height() - areaSize.height()) / charH + 1); painter.setPen(Qt::gray); painter.drawLine(xPosAscii, yPosStart, xPosAscii, yPosEnd); painter.setPen(Qt::black); int size = data_.size(); for (int lineIdx = firstLineIdx, yPos = yPosStart; lineIdx < lastLineIdx; lineIdx += 1, yPos += charH) { QByteArray part = data_.begin() + (lineIdx * acharInLine); int part_size = size / acharInLine ? acharInLine : size % acharInLine; part.resize(part_size); size -= part_size; QByteArray hex = part.toHex(); painter.setBackgroundMode(Qt::OpaqueMode); for (int xPos = xPosStart, i = 0; i < hex.size(); i++, xPos += 3 * charW) { QString val = hex.mid(i * 2, 2); QRect hexrect(xPos, yPos, 3 * charW, charH); painter.drawText(hexrect, Qt::AlignLeft, val); char ch = part[i]; if ((ch < 0x20) || (ch > 0x7e)) { part[i] = '.'; } } painter.setBackgroundMode(Qt::TransparentMode); QRect asciirect(xPosAsciiStart, yPos, acharInLine * charW, charH); painter.drawText(asciirect, Qt::AlignLeft, part); } } else { base_class::paintEvent(event); } }
byte *FontRenderer::buildTextSprite(byte *sentence, uint32 fontRes, uint8 pen, LineInfo *line, uint16 noOfLines) { uint16 i; // Find the width of the widest line in the output text uint16 spriteWidth = 0; for (i = 0; i < noOfLines; i++) if (line[i].width > spriteWidth) spriteWidth = line[i].width; // Check that text sprite has even horizontal resolution in PSX version // (needed to work around a problem in some sprites, which reports an odd // number as horiz resolution, but then have the next even number as true width) if (Sword2Engine::isPsx()) spriteWidth = (spriteWidth % 2) ? spriteWidth + 1 : spriteWidth; // Find the total height of the text sprite: the total height of the // text lines, plus the total height of the spacing between them. uint16 char_height = charHeight(fontRes); uint16 spriteHeight = char_height * noOfLines + _lineSpacing * (noOfLines - 1); // Allocate memory for the text sprite uint32 sizeOfSprite = spriteWidth * spriteHeight; byte *textSprite = (byte *)malloc(FrameHeader::size() + sizeOfSprite); // At this stage, textSprite points to an unmovable memory block. Set // up the frame header. FrameHeader frame_head; frame_head.compSize = 0; frame_head.width = spriteWidth; frame_head.height = spriteHeight; // Normally for PSX frame header we double the height // of the sprite artificially to regain correct aspect // ratio, but this is an "artificially generated" text // sprite, which gets created with correct aspect, so // fix the height. if (Sword2Engine::isPsx()) frame_head.height /= 2; frame_head.write(textSprite); debug(4, "Text sprite size: %ux%u", spriteWidth, spriteHeight); // Clear the entire sprite to make it transparent. byte *linePtr = textSprite + FrameHeader::size(); memset(linePtr, 0, sizeOfSprite); byte *charSet = _vm->_resman->openResource(fontRes); // Build the sprite, one line at a time uint16 pos = 0; for (i = 0; i < noOfLines; i++) { // Center each line byte *spritePtr = linePtr + (spriteWidth - line[i].width) / 2; // copy the sprite for each character in this line to the // text sprite and inc the sprite ptr by the character's // width minus the 'overlap' for (uint j = 0; j < line[i].length; j++) { byte *charPtr = findChar(sentence[pos++], charSet); frame_head.read(charPtr); assert(frame_head.height == char_height); copyChar(charPtr, spritePtr, spriteWidth, pen); // We must remember to free memory for generated character in psx, // as it is extracted differently than pc version (copyed from a // char atlas). if (Sword2Engine::isPsx()) free(charPtr); spritePtr += frame_head.width + _charSpacing; } // Skip space at end of last word in this line pos++; if (Sword2Engine::isPsx()) linePtr += (char_height / 2 + _lineSpacing) * spriteWidth; else linePtr += (char_height + _lineSpacing) * spriteWidth; } _vm->_resman->closeResource(fontRes); return textSprite; }
static int MapFont(char *font_name, const char *troff_name) { XFontStruct *fi; int count; char **names; FILE *out; unsigned int c; unsigned int attributes; XFontName parsed; int j, k; DviCharNameMap *char_map; char encoding[256]; char *s; int wid; char name_string[2048]; if (!XParseFontName(font_name, &parsed, &attributes)) { fprintf(stderr, "not a standard name: %s\n", font_name); return 0; } attributes &= ~(FontNamePixelSize | FontNameAverageWidth); attributes |= FontNameResolutionX; attributes |= FontNameResolutionY; attributes |= FontNamePointSize; parsed.ResolutionX = resolution; parsed.ResolutionY = resolution; parsed.PointSize = point_size * 10; XFormatFontName(&parsed, attributes, name_string); names = XListFonts(dpy, name_string, 100000, &count); if (count < 1) { fprintf(stderr, "bad font name: %s\n", font_name); return 0; } if (FontNamesAmbiguous(font_name, names, count)) return 0; XParseFontName(names[0], &parsed, &attributes); sprintf(encoding, "%s-%s", parsed.CharSetRegistry, parsed.CharSetEncoding); for (s = encoding; *s; s++) if (isupper(*s)) *s = tolower(*s); char_map = DviFindMap(encoding); if (!char_map) { fprintf(stderr, "not a standard encoding: %s\n", encoding); return 0; } fi = XLoadQueryFont(dpy, names[0]); if (!fi) { fprintf(stderr, "font does not exist: %s\n", names[0]); return 0; } printf("%s -> %s\n", names[0], troff_name); { /* Avoid race while opening file */ int fd; (void) unlink(troff_name); fd = open(troff_name, O_WRONLY | O_CREAT | O_EXCL, 0600); out = fdopen(fd, "w"); } if (!out) { perror(troff_name); return 0; } fprintf(out, "name %s\n", troff_name); if (!strcmp(char_map->encoding, "adobe-fontspecific")) fprintf(out, "special\n"); if (charExists(fi, ' ')) { int w = charWidth(fi, ' '); if (w > 0) fprintf(out, "spacewidth %d\n", w); } fprintf(out, "charset\n"); for (c = fi->min_char_or_byte2; c <= fi->max_char_or_byte2; c++) { const char *name = DviCharName(char_map, c, 0); if (charExists(fi, c)) { int param[5]; wid = charWidth(fi, c); fprintf(out, "%s\t%d", name ? name : "---", wid); param[0] = charHeight(fi, c); param[1] = charDepth(fi, c); param[2] = 0; /* charRBearing (fi, c) - wid */ param[3] = 0; /* charLBearing (fi, c) */ param[4] = 0; /* XXX */ for (j = 0; j < 5; j++) if (param[j] < 0) param[j] = 0; for (j = 4; j >= 0; j--) if (param[j] != 0) break; for (k = 0; k <= j; k++) fprintf(out, ",%d", param[k]); fprintf(out, "\t0\t0%o\n", c); if (name) { for (k = 1; DviCharName(char_map, c, k); k++) { fprintf(out, "%s\t\"\n", DviCharName(char_map, c, k)); } } } } XUnloadFont(dpy, fi->fid); fclose(out); return 1; }
float acBitmapFont::charTop(unsigned char c) { return charExists(c) ? (-charHeight(c) + (float)(topExtent[win2mac[c]-33]) / 64.0f) : 0; }
// Convert window pixels (x,y) to ASCII spaces (x,y). df::Position df::GraphicsManager::pixelsToSpaces(Position pixels){ return Position(pixels.getX() / charWidth(), pixels.getY() / charHeight()); }
// Convert ASCII spaces (x,y) to window pixels (x,y). df::Position df::GraphicsManager::spacesToPixels(Position spaces){ return Position(spaces.getX() * charWidth(), spaces.getY() * charHeight()); }