* Changed the AGGTextRenderer to use the new UTF8 handling
* Added more char codes to is_white_space(), should be all I think Sorry if I stepped on your toes Stephan, but I wanted these changes flushed before I leave for holidays :-). git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@16501 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
parent
6990418519
commit
20a4e7265c
|
@ -159,10 +159,8 @@ UTF8ToCharCode(const char **bytes)
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((*bytes)[0] == 0) {
|
if ((*bytes)[0] == 0) {
|
||||||
/* We do not advance beyond the terminating 0. Just pad any further
|
/* We do not advance beyond the terminating 0. */
|
||||||
request with spaces. */
|
return 0x00;
|
||||||
result += 0x20;
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
result += (*bytes)[0];
|
result += (*bytes)[0];
|
||||||
|
|
|
@ -81,11 +81,21 @@ CubicToFunc(FT_Vector *control1, FT_Vector *control2, FT_Vector *to, void *user)
|
||||||
|
|
||||||
|
|
||||||
inline bool
|
inline bool
|
||||||
is_white_space(uint16 glyph)
|
is_white_space(uint32 charCode)
|
||||||
{
|
{
|
||||||
// TODO: handle them all!
|
switch (charCode) {
|
||||||
if (glyph == ' ' || glyph == B_TAB)
|
case 0x0009: /* tab */
|
||||||
return true;
|
case 0x000b: /* vertical tab */
|
||||||
|
case 0x000c: /* form feed */
|
||||||
|
case 0x0020: /* space */
|
||||||
|
case 0x00a0: /* non breaking space */
|
||||||
|
case 0x000a: /* line feed */
|
||||||
|
case 0x000d: /* carriage return */
|
||||||
|
case 0x2028: /* line separator */
|
||||||
|
case 0x2029: /* paragraph separator */
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -428,10 +438,9 @@ ServerFont::GetEscapements(const char charArray[], int32 numChars,
|
||||||
|
|
||||||
const char *string = charArray;
|
const char *string = charArray;
|
||||||
for (int i = 0; i < numChars; i++) {
|
for (int i = 0; i < numChars; i++) {
|
||||||
// Do this first as UTF8ToCharCode advances string.
|
uint32 charCode = UTF8ToCharCode(&string);
|
||||||
escapementArray[i].x = is_white_space(*string) ? delta.space : delta.nonspace;
|
FT_Load_Char(face, charCode, FT_LOAD_NO_BITMAP);
|
||||||
|
escapementArray[i].x = is_white_space(charCode) ? delta.space : delta.nonspace;
|
||||||
FT_Load_Char(face, UTF8ToCharCode(&string), FT_LOAD_NO_BITMAP);
|
|
||||||
escapementArray[i].x += float(face->glyph->advance.x) / 64;
|
escapementArray[i].x += float(face->glyph->advance.x) / 64;
|
||||||
escapementArray[i].y = -float(face->glyph->advance.y) / 64;
|
escapementArray[i].y = -float(face->glyph->advance.y) / 64;
|
||||||
escapementArray[i].x /= fSize;
|
escapementArray[i].x /= fSize;
|
||||||
|
@ -466,10 +475,9 @@ ServerFont::GetEscapements(const char charArray[], int32 numChars,
|
||||||
|
|
||||||
const char *string = charArray;
|
const char *string = charArray;
|
||||||
for (int i = 0; i < numChars; i++) {
|
for (int i = 0; i < numChars; i++) {
|
||||||
// Do this first as UTF8ToCharCode advances string.
|
uint32 charCode = UTF8ToCharCode(&string);
|
||||||
widthArray[i] = is_white_space(*string) ? delta.space : delta.nonspace;
|
FT_Load_Char(face, charCode, FT_LOAD_NO_BITMAP);
|
||||||
|
widthArray[i] = is_white_space(charCode) ? delta.space : delta.nonspace;
|
||||||
FT_Load_Char(face, UTF8ToCharCode(&string), FT_LOAD_NO_BITMAP);
|
|
||||||
widthArray[i] += float(face->glyph->metrics.horiAdvance) / 64.0;
|
widthArray[i] += float(face->glyph->metrics.horiAdvance) / 64.0;
|
||||||
widthArray[i] /= fSize;
|
widthArray[i] /= fSize;
|
||||||
}
|
}
|
||||||
|
@ -493,14 +501,15 @@ ServerFont::GetBoundingBoxesAsString(const char charArray[], int32 numChars,
|
||||||
|
|
||||||
const char *string = charArray;
|
const char *string = charArray;
|
||||||
for (int i = 0; i < numChars; i++) {
|
for (int i = 0; i < numChars; i++) {
|
||||||
|
uint32 charCode = UTF8ToCharCode(&string);
|
||||||
if (stringEscapement) {
|
if (stringEscapement) {
|
||||||
if (i > 0)
|
if (i > 0)
|
||||||
rectArray[i].OffsetBy(is_white_space(*string) ? delta.space / 2.0 : delta.nonspace / 2.0, 0.0);
|
rectArray[i].OffsetBy(is_white_space(charCode) ? delta.space / 2.0 : delta.nonspace / 2.0, 0.0);
|
||||||
|
|
||||||
rectArray[i].OffsetBy(is_white_space(*string) ? delta.space / 2.0 : delta.nonspace / 2.0, 0.0);
|
rectArray[i].OffsetBy(is_white_space(charCode) ? delta.space / 2.0 : delta.nonspace / 2.0, 0.0);
|
||||||
}
|
}
|
||||||
|
|
||||||
FT_Load_Char(face, UTF8ToCharCode(&string), FT_LOAD_NO_BITMAP);
|
FT_Load_Char(face, charCode, FT_LOAD_NO_BITMAP);
|
||||||
if (i < numChars - 1) {
|
if (i < numChars - 1) {
|
||||||
rectArray[i + 1].left = rectArray[i + 1].right = rectArray[i].left
|
rectArray[i + 1].left = rectArray[i + 1].right = rectArray[i].left
|
||||||
+ face->glyph->metrics.horiAdvance / 64.0;
|
+ face->glyph->metrics.horiAdvance / 64.0;
|
||||||
|
|
|
@ -20,6 +20,7 @@
|
||||||
#include <agg_trans_affine.h>
|
#include <agg_trans_affine.h>
|
||||||
|
|
||||||
#include "AGGTextRenderer.h"
|
#include "AGGTextRenderer.h"
|
||||||
|
#include "moreUTF8.h"
|
||||||
|
|
||||||
#define FLIP_Y false
|
#define FLIP_Y false
|
||||||
|
|
||||||
|
@ -42,13 +43,22 @@ rect_to_int(BRect r,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// is_white_space
|
|
||||||
inline bool
|
inline bool
|
||||||
is_white_space(uint16 glyph)
|
is_white_space(uint32 charCode)
|
||||||
{
|
{
|
||||||
// TODO: handle them all!
|
switch (charCode) {
|
||||||
if (glyph == ' ' || glyph == B_TAB)
|
case 0x0009: /* tab */
|
||||||
return true;
|
case 0x000b: /* vertical tab */
|
||||||
|
case 0x000c: /* form feed */
|
||||||
|
case 0x0020: /* space */
|
||||||
|
case 0x00a0: /* non breaking space */
|
||||||
|
case 0x000a: /* line feed */
|
||||||
|
case 0x000d: /* carriage return */
|
||||||
|
case 0x2028: /* line separator */
|
||||||
|
case 0x2029: /* paragraph separator */
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -156,7 +166,7 @@ AGGTextRenderer::Unset()
|
||||||
// TODO ? release some kind of reference count on the ServerFont?
|
// TODO ? release some kind of reference count on the ServerFont?
|
||||||
}
|
}
|
||||||
|
|
||||||
// RenderString
|
|
||||||
BRect
|
BRect
|
||||||
AGGTextRenderer::RenderString(const char* string,
|
AGGTextRenderer::RenderString(const char* string,
|
||||||
uint32 length,
|
uint32 length,
|
||||||
|
@ -178,121 +188,121 @@ AGGTextRenderer::RenderString(const char* string,
|
||||||
Transformable transform(fEmbeddedTransformation);
|
Transformable transform(fEmbeddedTransformation);
|
||||||
transform.TranslateBy(baseLine);
|
transform.TranslateBy(baseLine);
|
||||||
|
|
||||||
uint32 glyphCount;
|
fCurves.approximation_scale(transform.scale());
|
||||||
|
|
||||||
if (_PrepareUnicodeBuffer(string, length, &glyphCount) >= B_OK) {
|
// use a transformation behind the curves
|
||||||
fCurves.approximation_scale(transform.scale());
|
// (only if glyph->data_type == agg::glyph_data_outline)
|
||||||
|
// in the pipeline for the rasterizer
|
||||||
|
typedef agg::conv_transform<conv_font_curve_type, agg::trans_affine>
|
||||||
|
conv_font_trans_type;
|
||||||
|
conv_font_trans_type transformedOutline(fCurves, transform);
|
||||||
|
|
||||||
// use a transformation behind the curves
|
double x = 0.0;
|
||||||
// (only if glyph->data_type == agg::glyph_data_outline)
|
double y0 = 0.0;
|
||||||
// in the pipeline for the rasterizer
|
double y = y0;
|
||||||
typedef agg::conv_transform<conv_font_curve_type, agg::trans_affine>
|
|
||||||
conv_font_trans_type;
|
|
||||||
conv_font_trans_type transformedOutline(fCurves, transform);
|
|
||||||
|
|
||||||
uint16* p = (uint16*)fUnicodeBuffer;
|
double advanceX = 0.0;
|
||||||
|
double advanceY = 0.0;
|
||||||
|
bool firstLoop = true;
|
||||||
|
|
||||||
double x = 0.0;
|
// for when we bypass the transformation pipeline
|
||||||
double y0 = 0.0;
|
BPoint transformOffset(0.0, 0.0);
|
||||||
double y = y0;
|
transform.Transform(&transformOffset);
|
||||||
|
|
||||||
double advanceX = 0.0;
|
uint32 charCode;
|
||||||
double advanceY = 0.0;
|
while ((charCode = UTF8ToCharCode(&string)) > 0) {
|
||||||
|
// line break (not supported by R5)
|
||||||
|
/*if (charCode == '\n') {
|
||||||
|
y0 += LineOffset();
|
||||||
|
x = 0.0;
|
||||||
|
y = y0;
|
||||||
|
advanceX = 0.0;
|
||||||
|
advanceY = 0.0;
|
||||||
|
continue;
|
||||||
|
}*/
|
||||||
|
|
||||||
// for when we bypass the transformation pipeline
|
const agg::glyph_cache* glyph = fFontCache.glyph(charCode);
|
||||||
BPoint transformOffset(0.0, 0.0);
|
|
||||||
transform.Transform(&transformOffset);
|
|
||||||
|
|
||||||
for (uint32 i = 0; i < glyphCount; i++) {
|
if (!glyph) {
|
||||||
/* // line break (not supported by R5)
|
if (charCode >= 0x20 && charCode < 0x80)
|
||||||
if (*p == '\n') {
|
fprintf(stderr, "failed to load glyph for '%c'\n", (char)charCode);
|
||||||
y0 += LineOffset();
|
else
|
||||||
x = 0.0;
|
fprintf(stderr, "failed to load glyph for 0x%04x\n", charCode);
|
||||||
y = y0;
|
continue;
|
||||||
advanceX = 0.0;
|
}
|
||||||
advanceY = 0.0;
|
|
||||||
++p;
|
|
||||||
continue;
|
|
||||||
}*/
|
|
||||||
|
|
||||||
const agg::glyph_cache* glyph = fFontCache.glyph(*p);
|
if (!firstLoop && fKerning)
|
||||||
|
fFontCache.add_kerning(&advanceX, &advanceY);
|
||||||
|
|
||||||
if (glyph) {
|
x += advanceX;
|
||||||
if (i > 0 && fKerning)
|
y += advanceY;
|
||||||
fFontCache.add_kerning(&advanceX, &advanceY);
|
|
||||||
|
|
||||||
x += advanceX;
|
if (delta)
|
||||||
y += advanceY;
|
x += is_white_space(charCode) ? delta->space : delta->nonspace;
|
||||||
|
|
||||||
if (delta)
|
// "glyphBounds" is the bounds of the glyph transformed
|
||||||
x += is_white_space(*p) ? delta->space : delta->nonspace;
|
// by the x y location of the glyph along the base line,
|
||||||
|
// it is therefor yet "untransformed".
|
||||||
|
const agg::rect& r = glyph->bounds;
|
||||||
|
BRect glyphBounds(r.x1 + x, r.y1 + y - 1, r.x2 + x + 1, r.y2 + y + 1);
|
||||||
|
// NOTE: "-1"/"+1" converts the glyph bounding box from pixel
|
||||||
|
// indices to pixel area coordinates
|
||||||
|
|
||||||
// "glyphBounds" is the bounds of the glyph transformed
|
// track bounding box
|
||||||
// by the x y location of the glyph along the base line,
|
if (glyphBounds.IsValid())
|
||||||
// it is therefor yet "untransformed".
|
bounds = bounds.IsValid() ? bounds | glyphBounds : glyphBounds;
|
||||||
const agg::rect& r = glyph->bounds;
|
|
||||||
BRect glyphBounds(r.x1 + x, r.y1 + y - 1, r.x2 + x + 1, r.y2 + y + 1);
|
|
||||||
// NOTE: "-1"/"+ 1" converts the glyph bounding box from pixel
|
|
||||||
// indices to pixel area coordinates
|
|
||||||
|
|
||||||
// track bounding box
|
// render the glyph if this is not a dry run
|
||||||
if (glyphBounds.IsValid())
|
if (!dryRun) {
|
||||||
bounds = bounds.IsValid() ? bounds | glyphBounds : glyphBounds;
|
// init the fontmanager's embedded adaptors
|
||||||
|
// NOTE: The initialization for the "location" of
|
||||||
|
// the glyph is different depending on wether we
|
||||||
|
// deal with non-(rotated/sheared) text, in which
|
||||||
|
// case we have a native FT bitmap. For rotated or
|
||||||
|
// sheared text, we use AGG vector outlines and
|
||||||
|
// a transformation pipeline, which will be applied
|
||||||
|
// _after_ we retrieve the outline, and that's why
|
||||||
|
// we simply pass x and y, which are untransformed.
|
||||||
|
|
||||||
// render the glyph if this is not a dry run
|
// "glyphBounds" is now transformed into screen coords
|
||||||
if (!dryRun) {
|
// in order to stop drawing when we are already outside
|
||||||
// init the fontmanager's embedded adaptors
|
// of the clipping frame
|
||||||
// NOTE: The initialization for the "location" of
|
if (glyph->data_type != agg::glyph_data_outline) {
|
||||||
// the glyph is different depending on wether we
|
// we cannot use the transformation pipeline
|
||||||
// deal with non-(rotated/sheared) text, in which
|
double transformedX = x + transformOffset.x;
|
||||||
// case we have a native FT bitmap. For rotated or
|
double transformedY = y + transformOffset.y;
|
||||||
// sheared text, we use AGG vector outlines and
|
fFontCache.init_embedded_adaptors(glyph,
|
||||||
// a transformation pipeline, which will be applied
|
transformedX, transformedY);
|
||||||
// _after_ we retrieve the outline, and that's why
|
glyphBounds.OffsetBy(transformOffset);
|
||||||
// we simply pass x and y, which are untransformed.
|
} else {
|
||||||
|
fFontCache.init_embedded_adaptors(glyph, x, y);
|
||||||
// "glyphBounds" is now transformed into screen coords
|
glyphBounds = transform.TransformBounds(glyphBounds);
|
||||||
// in order to stop drawing when we are already outside
|
}
|
||||||
// of the clipping frame
|
|
||||||
if (glyph->data_type != agg::glyph_data_outline) {
|
|
||||||
// we cannot use the transformation pipeline
|
|
||||||
double transformedX = x + transformOffset.x;
|
|
||||||
double transformedY = y + transformOffset.y;
|
|
||||||
fFontCache.init_embedded_adaptors(glyph,
|
|
||||||
transformedX,
|
|
||||||
transformedY);
|
|
||||||
glyphBounds.OffsetBy(transformOffset);
|
|
||||||
} else {
|
|
||||||
fFontCache.init_embedded_adaptors(glyph, x, y);
|
|
||||||
glyphBounds = transform.TransformBounds(glyphBounds);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (clippingFrame.Intersects(glyphBounds)) {
|
if (clippingFrame.Intersects(glyphBounds)) {
|
||||||
switch (glyph->data_type) {
|
switch (glyph->data_type) {
|
||||||
case agg::glyph_data_mono:
|
case agg::glyph_data_mono:
|
||||||
agg::render_scanlines(fFontCache.mono_adaptor(),
|
agg::render_scanlines(fFontCache.mono_adaptor(),
|
||||||
fFontCache.mono_scanline(),
|
fFontCache.mono_scanline(), *binRenderer);
|
||||||
*binRenderer);
|
break;
|
||||||
break;
|
|
||||||
|
|
||||||
case agg::glyph_data_gray8:
|
case agg::glyph_data_gray8:
|
||||||
agg::render_scanlines(fFontCache.gray8_adaptor(),
|
agg::render_scanlines(fFontCache.gray8_adaptor(),
|
||||||
fFontCache.gray8_scanline(),
|
fFontCache.gray8_scanline(), *solidRenderer);
|
||||||
*solidRenderer);
|
break;
|
||||||
break;
|
|
||||||
|
case agg::glyph_data_outline: {
|
||||||
case agg::glyph_data_outline: {
|
fRasterizer.reset();
|
||||||
fRasterizer.reset();
|
// NOTE: this function can be easily extended to handle
|
||||||
// NOTE: this function can be easily extended to handle
|
// conversion to contours, so that's why there is a lot of
|
||||||
// conversion to contours, so that's why there is a lot of
|
// commented out code, I leave it here because I think it
|
||||||
// commented out code, I leave it here because I think it
|
// will be needed again.
|
||||||
// will be needed again.
|
|
||||||
|
//if(fabs(0.0) <= 0.01) {
|
||||||
// if(fabs(0.0) <= 0.01) {
|
// For the sake of efficiency skip the
|
||||||
// For the sake of efficiency skip the
|
// contour converter if the weight is about zero.
|
||||||
// contour converter if the weight is about zero.
|
|
||||||
//-----------------------
|
fRasterizer.add_path(transformedOutline);
|
||||||
fRasterizer.add_path(transformedOutline);
|
|
||||||
#if SHOW_GLYPH_BOUNDS
|
#if SHOW_GLYPH_BOUNDS
|
||||||
agg::path_storage p;
|
agg::path_storage p;
|
||||||
p.move_to(glyphBounds.left + 0.5, glyphBounds.top + 0.5);
|
p.move_to(glyphBounds.left + 0.5, glyphBounds.top + 0.5);
|
||||||
|
@ -304,51 +314,42 @@ AGGTextRenderer::RenderString(const char* string,
|
||||||
ps.width(1.0);
|
ps.width(1.0);
|
||||||
fRasterizer.add_path(ps);
|
fRasterizer.add_path(ps);
|
||||||
#endif
|
#endif
|
||||||
/* } else {
|
/*} else {
|
||||||
// fRasterizer.add_path(fContour);
|
//fRasterizer.add_path(fContour);
|
||||||
fRasterizer.add_path(transformedOutline);
|
fRasterizer.add_path(transformedOutline);
|
||||||
}*/
|
}*/
|
||||||
agg::render_scanlines(fRasterizer, fScanline, *solidRenderer);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// increment pen position
|
agg::render_scanlines(fRasterizer, fScanline, *solidRenderer);
|
||||||
advanceX = glyph->advance_x;
|
break;
|
||||||
advanceY = glyph->advance_y;
|
}
|
||||||
} else {
|
default:
|
||||||
if (*p < 128) {
|
break;
|
||||||
char c[2];
|
|
||||||
c[0] = (uint8)*p;
|
|
||||||
c[1] = 0;
|
|
||||||
fprintf(stderr, "failed to load glyph for '%s'\n", c);
|
|
||||||
} else {
|
|
||||||
fprintf(stderr, "failed to load glyph for %d\n", *p);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
++p;
|
|
||||||
}
|
}
|
||||||
// put pen location behind rendered text
|
|
||||||
// (at the baseline of the virtual next glyph)
|
|
||||||
if (nextCharPos) {
|
|
||||||
nextCharPos->x = x + advanceX;
|
|
||||||
nextCharPos->y = y + advanceY;
|
|
||||||
|
|
||||||
transform.Transform(nextCharPos);
|
// increment pen position
|
||||||
}
|
advanceX = glyph->advance_x;
|
||||||
|
advanceY = glyph->advance_y;
|
||||||
|
|
||||||
|
firstLoop = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
// put pen location behind rendered text
|
||||||
|
// (at the baseline of the virtual next glyph)
|
||||||
|
if (nextCharPos) {
|
||||||
|
nextCharPos->x = x + advanceX;
|
||||||
|
nextCharPos->y = y + advanceY;
|
||||||
|
|
||||||
|
transform.Transform(nextCharPos);
|
||||||
}
|
}
|
||||||
|
|
||||||
return transform.TransformBounds(bounds);
|
return transform.TransformBounds(bounds);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// StringWidth
|
|
||||||
double
|
double
|
||||||
AGGTextRenderer::StringWidth(const char* utf8String, uint32 length)
|
AGGTextRenderer::StringWidth(const char* string, uint32 length)
|
||||||
{
|
{
|
||||||
// NOTE: The implementation does not take font rotation (or shear)
|
// NOTE: The implementation does not take font rotation (or shear)
|
||||||
// into account. Just like on R5. Should it ever be desirable to
|
// into account. Just like on R5. Should it ever be desirable to
|
||||||
|
@ -361,69 +362,25 @@ AGGTextRenderer::StringWidth(const char* utf8String, uint32 length)
|
||||||
// Note that shear will not have any influence on the baseline though.
|
// Note that shear will not have any influence on the baseline though.
|
||||||
|
|
||||||
double width = 0.0;
|
double width = 0.0;
|
||||||
uint32 glyphCount;
|
uint32 charCode;
|
||||||
if (_PrepareUnicodeBuffer(utf8String, length, &glyphCount) >= B_OK) {
|
double y = 0.0;
|
||||||
uint16* p = (uint16*)fUnicodeBuffer;
|
const agg::glyph_cache* glyph;
|
||||||
|
bool firstLoop = true;
|
||||||
|
|
||||||
double y = 0.0;
|
while ((charCode = UTF8ToCharCode(&string)) > 0) {
|
||||||
const agg::glyph_cache* glyph;
|
glyph = fFontCache.glyph(charCode);
|
||||||
|
if (glyph) {
|
||||||
for (uint32 i = 0; i < glyphCount; i++) {
|
if (!firstLoop && fKerning)
|
||||||
if ((glyph = fFontCache.glyph(*p))) {
|
fFontCache.add_kerning(&width, &y);
|
||||||
if (i > 0 && fKerning)
|
width += glyph->advance_x;
|
||||||
fFontCache.add_kerning(&width, &y);
|
|
||||||
|
|
||||||
width += glyph->advance_x;
|
|
||||||
}
|
|
||||||
++p;
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
firstLoop = false;
|
||||||
|
};
|
||||||
|
|
||||||
return width;
|
return width;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// _PrepareUnicodeBuffer
|
|
||||||
status_t
|
|
||||||
AGGTextRenderer::_PrepareUnicodeBuffer(const char* utf8String,
|
|
||||||
uint32 length, uint32* glyphCount)
|
|
||||||
{
|
|
||||||
if (length == 0) {
|
|
||||||
*glyphCount = 0;
|
|
||||||
return B_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
int32 srcLength = length;
|
|
||||||
int32 dstLength = srcLength * 4;
|
|
||||||
|
|
||||||
// take care of adjusting buffer size
|
|
||||||
if (dstLength > fUnicodeBufferSize) {
|
|
||||||
fUnicodeBufferSize = dstLength;
|
|
||||||
fUnicodeBuffer = (char*)realloc((void*)fUnicodeBuffer, fUnicodeBufferSize);
|
|
||||||
}
|
|
||||||
|
|
||||||
status_t ret;
|
|
||||||
if (!fUnicodeBuffer) {
|
|
||||||
ret = B_NO_MEMORY;
|
|
||||||
} else {
|
|
||||||
int32 state = 0;
|
|
||||||
ret = convert_from_utf8(B_UNICODE_CONVERSION,
|
|
||||||
utf8String, &srcLength,
|
|
||||||
fUnicodeBuffer, &dstLength,
|
|
||||||
&state, B_SUBSTITUTE);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ret >= B_OK) {
|
|
||||||
*glyphCount = (uint32)(dstLength / 2);
|
|
||||||
ret = swap_data(B_INT16_TYPE, fUnicodeBuffer, dstLength,
|
|
||||||
B_SWAP_BENDIAN_TO_HOST);
|
|
||||||
} else {
|
|
||||||
*glyphCount = 0;
|
|
||||||
fprintf(stderr, "AGGTextRenderer::_PrepareUnicodeBuffer() - UTF8 -> Unicode conversion failed: %s\n", strerror(ret));
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
// _UpdateSizeAndHinting
|
// _UpdateSizeAndHinting
|
||||||
void
|
void
|
||||||
AGGTextRenderer::_UpdateSizeAndHinting(float size, bool hinted, bool force)
|
AGGTextRenderer::_UpdateSizeAndHinting(float size, bool hinted, bool force)
|
||||||
|
|
|
@ -48,9 +48,6 @@ class AGGTextRenderer {
|
||||||
uint32 length);
|
uint32 length);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
status_t _PrepareUnicodeBuffer(const char* utf8String,
|
|
||||||
uint32 length,
|
|
||||||
uint32* glyphCount);
|
|
||||||
void _UpdateSizeAndHinting(float size, bool hinted,
|
void _UpdateSizeAndHinting(float size, bool hinted,
|
||||||
bool force = false);
|
bool force = false);
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue