summaryrefslogtreecommitdiff
path: root/indra/llrender/llfontfreetypesvg.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'indra/llrender/llfontfreetypesvg.cpp')
-rw-r--r--indra/llrender/llfontfreetypesvg.cpp262
1 files changed, 131 insertions, 131 deletions
diff --git a/indra/llrender/llfontfreetypesvg.cpp b/indra/llrender/llfontfreetypesvg.cpp
index 19d327a4c9..355e8432aa 100644
--- a/indra/llrender/llfontfreetypesvg.cpp
+++ b/indra/llrender/llfontfreetypesvg.cpp
@@ -44,21 +44,21 @@
struct LLSvgRenderData
{
- FT_UInt GlyphIndex = 0;
- FT_Error Error = FT_Err_Ok; // FreeType currently (@2.12.1) ignores the error value returned by the preset glyph slot callback so we return it at render time
- // (See https://github.com/freetype/freetype/blob/5faa1df8b93ebecf0f8fd5fe8fda7b9082eddced/src/base/ftobjs.c#L1170)
- NSVGimage* pNSvgImage = nullptr;
- float Scale = 0.f;
+ FT_UInt GlyphIndex = 0;
+ FT_Error Error = FT_Err_Ok; // FreeType currently (@2.12.1) ignores the error value returned by the preset glyph slot callback so we return it at render time
+ // (See https://github.com/freetype/freetype/blob/5faa1df8b93ebecf0f8fd5fe8fda7b9082eddced/src/base/ftobjs.c#L1170)
+ NSVGimage* pNSvgImage = nullptr;
+ float Scale = 0.f;
};
// static
FT_Error LLFontFreeTypeSvgRenderer::OnInit(FT_Pointer* state)
{
- // The SVG driver hook state is shared across all callback invocations; since our state is lightweight
- // we store it in the glyph instead.
- *state = nullptr;
+ // The SVG driver hook state is shared across all callback invocations; since our state is lightweight
+ // we store it in the glyph instead.
+ *state = nullptr;
- return FT_Err_Ok;
+ return FT_Err_Ok;
}
// static
@@ -69,137 +69,137 @@ void LLFontFreeTypeSvgRenderer::OnFree(FT_Pointer* state)
// static
void LLFontFreeTypeSvgRenderer::OnDataFinalizer(void* objectp)
{
- FT_GlyphSlot glyph_slot = static_cast<FT_GlyphSlot>(objectp);
+ FT_GlyphSlot glyph_slot = static_cast<FT_GlyphSlot>(objectp);
- LLSvgRenderData* pData = static_cast<LLSvgRenderData*>(glyph_slot->generic.data);
- glyph_slot->generic.data = nullptr;
- glyph_slot->generic.finalizer = nullptr;
- delete(pData);
+ LLSvgRenderData* pData = static_cast<LLSvgRenderData*>(glyph_slot->generic.data);
+ glyph_slot->generic.data = nullptr;
+ glyph_slot->generic.finalizer = nullptr;
+ delete(pData);
}
//static
FT_Error LLFontFreeTypeSvgRenderer::OnPresetGlypthSlot(FT_GlyphSlot glyph_slot, FT_Bool cache, FT_Pointer*)
{
- FT_SVG_Document document = static_cast<FT_SVG_Document>(glyph_slot->other);
-
- llassert(!glyph_slot->generic.data || !cache || glyph_slot->glyph_index == ((LLSvgRenderData*)glyph_slot->generic.data)->GlyphIndex);
- if (!glyph_slot->generic.data)
- {
- glyph_slot->generic.data = new LLSvgRenderData();
- glyph_slot->generic.finalizer = LLFontFreeTypeSvgRenderer::OnDataFinalizer;
- }
- LLSvgRenderData* datap = static_cast<LLSvgRenderData*>(glyph_slot->generic.data);
- if (!cache)
- {
- datap->GlyphIndex = glyph_slot->glyph_index;
- datap->Error = FT_Err_Ok;
- }
-
- // NOTE: nsvgParse modifies the input string so we need a temporary copy
- llassert(!datap->pNSvgImage || cache);
- if (!datap->pNSvgImage)
- {
- char* document_buffer = new char[document->svg_document_length + 1];
- memcpy(document_buffer, document->svg_document, document->svg_document_length);
- document_buffer[document->svg_document_length] = '\0';
-
- datap->pNSvgImage = nsvgParse(document_buffer, "px", 0.);
-
- delete[] document_buffer;
- }
-
- if (!datap->pNSvgImage)
- {
- datap->Error = FT_Err_Invalid_SVG_Document;
- return FT_Err_Invalid_SVG_Document;
- }
-
- // We don't (currently) support transformations so test for an identity rotation matrix + zero translation
- if (document->transform.xx != 1 << 16 || document->transform.yx != 0 ||
- document->transform.xy != 0 || document->transform.yy != 1 << 16 ||
- document->delta.x > 0 || document->delta.y > 0)
- {
- datap->Error = FT_Err_Unimplemented_Feature;
- return FT_Err_Unimplemented_Feature;
- }
-
- float svg_width = datap->pNSvgImage->width;
- float svg_height = datap->pNSvgImage->height;
- if (svg_width == 0.f || svg_height == 0.f)
- {
- svg_width = document->units_per_EM;
- svg_height = document->units_per_EM;
- }
-
- float svg_x_scale = (float)document->metrics.x_ppem / floorf(svg_width);
- float svg_y_scale = (float)document->metrics.y_ppem / floorf(svg_height);
- float svg_scale = llmin(svg_x_scale, svg_y_scale);
- datap->Scale = svg_scale;
-
- glyph_slot->bitmap.width = floorf(svg_width) * svg_scale;
- glyph_slot->bitmap.rows = floorf(svg_height) * svg_scale;
- glyph_slot->bitmap_left = (document->metrics.x_ppem - glyph_slot->bitmap.width) / 2;
- glyph_slot->bitmap_top = glyph_slot->face->size->metrics.ascender / 64.f;
- glyph_slot->bitmap.pitch = glyph_slot->bitmap.width * 4;
- glyph_slot->bitmap.pixel_mode = FT_PIXEL_MODE_BGRA;
-
- /* Copied as-is from fcft (MIT license) */
-
- // Compute all the bearings and set them correctly. The outline is scaled already, we just need to use the bounding box.
- float horiBearingX = 0.;
- float horiBearingY = -glyph_slot->bitmap_top;
-
- // XXX parentheses correct?
- float vertBearingX = glyph_slot->metrics.horiBearingX / 64.0f - glyph_slot->metrics.horiAdvance / 64.0f / 2;
- float vertBearingY = (glyph_slot->metrics.vertAdvance / 64.0f - glyph_slot->metrics.height / 64.0f) / 2;
-
- // Do conversion in two steps to avoid 'bad function cast' warning
- glyph_slot->metrics.width = glyph_slot->bitmap.width * 64;
- glyph_slot->metrics.height = glyph_slot->bitmap.rows * 64;
- glyph_slot->metrics.horiBearingX = horiBearingX * 64;
- glyph_slot->metrics.horiBearingY = horiBearingY * 64;
- glyph_slot->metrics.vertBearingX = vertBearingX * 64;
- glyph_slot->metrics.vertBearingY = vertBearingY * 64;
- if (glyph_slot->metrics.vertAdvance == 0)
- {
- glyph_slot->metrics.vertAdvance = glyph_slot->bitmap.rows * 1.2f * 64;
- }
-
- return FT_Err_Ok;
+ FT_SVG_Document document = static_cast<FT_SVG_Document>(glyph_slot->other);
+
+ llassert(!glyph_slot->generic.data || !cache || glyph_slot->glyph_index == ((LLSvgRenderData*)glyph_slot->generic.data)->GlyphIndex);
+ if (!glyph_slot->generic.data)
+ {
+ glyph_slot->generic.data = new LLSvgRenderData();
+ glyph_slot->generic.finalizer = LLFontFreeTypeSvgRenderer::OnDataFinalizer;
+ }
+ LLSvgRenderData* datap = static_cast<LLSvgRenderData*>(glyph_slot->generic.data);
+ if (!cache)
+ {
+ datap->GlyphIndex = glyph_slot->glyph_index;
+ datap->Error = FT_Err_Ok;
+ }
+
+ // NOTE: nsvgParse modifies the input string so we need a temporary copy
+ llassert(!datap->pNSvgImage || cache);
+ if (!datap->pNSvgImage)
+ {
+ char* document_buffer = new char[document->svg_document_length + 1];
+ memcpy(document_buffer, document->svg_document, document->svg_document_length);
+ document_buffer[document->svg_document_length] = '\0';
+
+ datap->pNSvgImage = nsvgParse(document_buffer, "px", 0.);
+
+ delete[] document_buffer;
+ }
+
+ if (!datap->pNSvgImage)
+ {
+ datap->Error = FT_Err_Invalid_SVG_Document;
+ return FT_Err_Invalid_SVG_Document;
+ }
+
+ // We don't (currently) support transformations so test for an identity rotation matrix + zero translation
+ if (document->transform.xx != 1 << 16 || document->transform.yx != 0 ||
+ document->transform.xy != 0 || document->transform.yy != 1 << 16 ||
+ document->delta.x > 0 || document->delta.y > 0)
+ {
+ datap->Error = FT_Err_Unimplemented_Feature;
+ return FT_Err_Unimplemented_Feature;
+ }
+
+ float svg_width = datap->pNSvgImage->width;
+ float svg_height = datap->pNSvgImage->height;
+ if (svg_width == 0.f || svg_height == 0.f)
+ {
+ svg_width = document->units_per_EM;
+ svg_height = document->units_per_EM;
+ }
+
+ float svg_x_scale = (float)document->metrics.x_ppem / floorf(svg_width);
+ float svg_y_scale = (float)document->metrics.y_ppem / floorf(svg_height);
+ float svg_scale = llmin(svg_x_scale, svg_y_scale);
+ datap->Scale = svg_scale;
+
+ glyph_slot->bitmap.width = floorf(svg_width) * svg_scale;
+ glyph_slot->bitmap.rows = floorf(svg_height) * svg_scale;
+ glyph_slot->bitmap_left = (document->metrics.x_ppem - glyph_slot->bitmap.width) / 2;
+ glyph_slot->bitmap_top = glyph_slot->face->size->metrics.ascender / 64.f;
+ glyph_slot->bitmap.pitch = glyph_slot->bitmap.width * 4;
+ glyph_slot->bitmap.pixel_mode = FT_PIXEL_MODE_BGRA;
+
+ /* Copied as-is from fcft (MIT license) */
+
+ // Compute all the bearings and set them correctly. The outline is scaled already, we just need to use the bounding box.
+ float horiBearingX = 0.;
+ float horiBearingY = -glyph_slot->bitmap_top;
+
+ // XXX parentheses correct?
+ float vertBearingX = glyph_slot->metrics.horiBearingX / 64.0f - glyph_slot->metrics.horiAdvance / 64.0f / 2;
+ float vertBearingY = (glyph_slot->metrics.vertAdvance / 64.0f - glyph_slot->metrics.height / 64.0f) / 2;
+
+ // Do conversion in two steps to avoid 'bad function cast' warning
+ glyph_slot->metrics.width = glyph_slot->bitmap.width * 64;
+ glyph_slot->metrics.height = glyph_slot->bitmap.rows * 64;
+ glyph_slot->metrics.horiBearingX = horiBearingX * 64;
+ glyph_slot->metrics.horiBearingY = horiBearingY * 64;
+ glyph_slot->metrics.vertBearingX = vertBearingX * 64;
+ glyph_slot->metrics.vertBearingY = vertBearingY * 64;
+ if (glyph_slot->metrics.vertAdvance == 0)
+ {
+ glyph_slot->metrics.vertAdvance = glyph_slot->bitmap.rows * 1.2f * 64;
+ }
+
+ return FT_Err_Ok;
}
// static
FT_Error LLFontFreeTypeSvgRenderer::OnRender(FT_GlyphSlot glyph_slot, FT_Pointer*)
{
- LLSvgRenderData* datap = static_cast<LLSvgRenderData*>(glyph_slot->generic.data);
- llassert(FT_Err_Ok == datap->Error);
- if (FT_Err_Ok != datap->Error)
- {
- return datap->Error;
- }
-
- // Render to glyph bitmap
- NSVGrasterizer* nsvgRasterizer = nsvgCreateRasterizer();
- nsvgRasterize(nsvgRasterizer, datap->pNSvgImage, 0, 0, datap->Scale, glyph_slot->bitmap.buffer, glyph_slot->bitmap.width, glyph_slot->bitmap.rows, glyph_slot->bitmap.pitch);
- nsvgDeleteRasterizer(nsvgRasterizer);
- nsvgDelete(datap->pNSvgImage);
- datap->pNSvgImage = nullptr;
-
- // Convert from RGBA to BGRA
- U32* pixel_buffer = (U32*)glyph_slot->bitmap.buffer; U8* byte_buffer = glyph_slot->bitmap.buffer;
- for (size_t y = 0, h = glyph_slot->bitmap.rows; y < h; y++)
- {
- for (size_t x = 0, w = glyph_slot->bitmap.pitch / 4; x < w; x++)
- {
- size_t pixel_idx = y * w + x;
- size_t byte_idx = pixel_idx * 4;
- U8 alpha = byte_buffer[byte_idx + 3];
- // Store as ARGB (*TODO - do we still have to care about endianness?)
- pixel_buffer[y * w + x] = alpha << 24 | (byte_buffer[byte_idx] * alpha / 0xFF) << 16 | (byte_buffer[byte_idx + 1] * alpha / 0xFF) << 8 | (byte_buffer[byte_idx + 2] * alpha / 0xFF);
- }
- }
-
- glyph_slot->format = FT_GLYPH_FORMAT_BITMAP;
- glyph_slot->bitmap.pixel_mode = FT_PIXEL_MODE_BGRA;
- return FT_Err_Ok;
+ LLSvgRenderData* datap = static_cast<LLSvgRenderData*>(glyph_slot->generic.data);
+ llassert(FT_Err_Ok == datap->Error);
+ if (FT_Err_Ok != datap->Error)
+ {
+ return datap->Error;
+ }
+
+ // Render to glyph bitmap
+ NSVGrasterizer* nsvgRasterizer = nsvgCreateRasterizer();
+ nsvgRasterize(nsvgRasterizer, datap->pNSvgImage, 0, 0, datap->Scale, glyph_slot->bitmap.buffer, glyph_slot->bitmap.width, glyph_slot->bitmap.rows, glyph_slot->bitmap.pitch);
+ nsvgDeleteRasterizer(nsvgRasterizer);
+ nsvgDelete(datap->pNSvgImage);
+ datap->pNSvgImage = nullptr;
+
+ // Convert from RGBA to BGRA
+ U32* pixel_buffer = (U32*)glyph_slot->bitmap.buffer; U8* byte_buffer = glyph_slot->bitmap.buffer;
+ for (size_t y = 0, h = glyph_slot->bitmap.rows; y < h; y++)
+ {
+ for (size_t x = 0, w = glyph_slot->bitmap.pitch / 4; x < w; x++)
+ {
+ size_t pixel_idx = y * w + x;
+ size_t byte_idx = pixel_idx * 4;
+ U8 alpha = byte_buffer[byte_idx + 3];
+ // Store as ARGB (*TODO - do we still have to care about endianness?)
+ pixel_buffer[y * w + x] = alpha << 24 | (byte_buffer[byte_idx] * alpha / 0xFF) << 16 | (byte_buffer[byte_idx + 1] * alpha / 0xFF) << 8 | (byte_buffer[byte_idx + 2] * alpha / 0xFF);
+ }
+ }
+
+ glyph_slot->format = FT_GLYPH_FORMAT_BITMAP;
+ glyph_slot->bitmap.pixel_mode = FT_PIXEL_MODE_BGRA;
+ return FT_Err_Ok;
}