summaryrefslogtreecommitdiffstats
path: root/src/extension
diff options
context:
space:
mode:
authorLiam P. White <inkscapebrony@gmail.com>2014-11-24 03:07:36 +0000
committerLiam P. White <inkscapebrony@gmail.com>2014-11-24 03:07:36 +0000
commitf12a73dd77175bd6126319f3a698eb16193e7b68 (patch)
treeb5a59803e5bd212f0e355faa029295aa79d47a0e /src/extension
parentUpdate to trunk r13690 (diff)
parentExtensions: try to calculate the SVG unit (diff)
downloadinkscape-f12a73dd77175bd6126319f3a698eb16193e7b68.tar.gz
inkscape-f12a73dd77175bd6126319f3a698eb16193e7b68.zip
Update to trunk r13750
(bzr r13341.5.23)
Diffstat (limited to 'src/extension')
-rw-r--r--src/extension/internal/cairo-renderer.cpp164
-rw-r--r--src/extension/internal/latex-text-renderer.cpp100
-rw-r--r--src/extension/internal/latex-text-renderer.h12
3 files changed, 152 insertions, 124 deletions
diff --git a/src/extension/internal/cairo-renderer.cpp b/src/extension/internal/cairo-renderer.cpp
index 1d9bb09d0..5a9a28ef9 100644
--- a/src/extension/internal/cairo-renderer.cpp
+++ b/src/extension/internal/cairo-renderer.cpp
@@ -147,13 +147,13 @@ Here comes the rendering part which could be put into the 'render' methods of SP
/* The below functions are copy&pasted plus slightly modified from *_invoke_print functions. */
static void sp_item_invoke_render(SPItem *item, CairoRenderContext *ctx);
-static void sp_group_render(SPItem *item, CairoRenderContext *ctx);
-static void sp_use_render(SPItem *item, CairoRenderContext *ctx);
-static void sp_shape_render(SPItem *item, CairoRenderContext *ctx);
-static void sp_text_render(SPItem *item, CairoRenderContext *ctx);
-static void sp_flowtext_render(SPItem *item, CairoRenderContext *ctx);
-static void sp_image_render(SPItem *item, CairoRenderContext *ctx);
-static void sp_symbol_render(SPItem *item, CairoRenderContext *ctx);
+static void sp_group_render(SPGroup *group, CairoRenderContext *ctx);
+static void sp_use_render(SPUse *use, CairoRenderContext *ctx);
+static void sp_shape_render(SPShape *shape, CairoRenderContext *ctx);
+static void sp_text_render(SPText *text, CairoRenderContext *ctx);
+static void sp_flowtext_render(SPFlowtext *flowtext, CairoRenderContext *ctx);
+static void sp_image_render(SPImage *image, CairoRenderContext *ctx);
+static void sp_symbol_render(SPSymbol *symbol, CairoRenderContext *ctx);
static void sp_asbitmap_render(SPItem *item, CairoRenderContext *ctx);
static void sp_shape_render_invoke_marker_rendering(SPMarker* marker, Geom::Affine tr, SPStyle* style, CairoRenderContext *ctx)
@@ -179,17 +179,15 @@ static void sp_shape_render_invoke_marker_rendering(SPMarker* marker, Geom::Affi
}
}
-static void sp_shape_render (SPItem *item, CairoRenderContext *ctx)
+static void sp_shape_render(SPShape *shape, CairoRenderContext *ctx)
{
- SPShape *shape = SP_SHAPE(item);
-
if (!shape->_curve) {
return;
}
- Geom::OptRect pbox = item->geometricBounds();
+ Geom::OptRect pbox = shape->geometricBounds();
- SPStyle* style = item->style;
+ SPStyle* style = shape->style;
Geom::PathVector const & pathv = shape->_curve->get_pathvector();
if (pathv.empty()) {
@@ -201,7 +199,7 @@ static void sp_shape_render (SPItem *item, CairoRenderContext *ctx)
// START marker
for (int i = 0; i < 2; i++) { // SP_MARKER_LOC and SP_MARKER_LOC_START
if ( shape->_marker[i] ) {
- SPMarker* marker = SP_MARKER (shape->_marker[i]);
+ SPMarker* marker = shape->_marker[i];
Geom::Affine tr;
if (marker->orient_mode == MARKER_ORIENT_AUTO) {
tr = sp_shape_marker_get_transform_at_start(pathv.begin()->front());
@@ -216,7 +214,7 @@ static void sp_shape_render (SPItem *item, CairoRenderContext *ctx)
// MID marker
for (int i = 0; i < 3; i += 2) { // SP_MARKER_LOC and SP_MARKER_LOC_MID
if ( !shape->_marker[i] ) continue;
- SPMarker* marker = SP_MARKER (shape->_marker[i]);
+ SPMarker* marker = shape->_marker[i];
for(Geom::PathVector::const_iterator path_it = pathv.begin(); path_it != pathv.end(); ++path_it) {
// START position
if ( path_it != pathv.begin()
@@ -268,7 +266,7 @@ static void sp_shape_render (SPItem *item, CairoRenderContext *ctx)
// END marker
for (int i = 0; i < 4; i += 3) { // SP_MARKER_LOC and SP_MARKER_LOC_END
if ( shape->_marker[i] ) {
- SPMarker* marker = SP_MARKER (shape->_marker[i]);
+ SPMarker* marker = shape->_marker[i];
/* Get reference to last curve in the path.
* For moveto-only path, this returns the "closing line segment". */
@@ -291,26 +289,25 @@ static void sp_shape_render (SPItem *item, CairoRenderContext *ctx)
}
}
-static void sp_group_render(SPItem *item, CairoRenderContext *ctx)
+static void sp_group_render(SPGroup *group, CairoRenderContext *ctx)
{
- SPGroup *group = SP_GROUP(item);
CairoRenderer *renderer = ctx->getRenderer();
TRACE(("sp_group_render opacity: %f\n", SP_SCALE24_TO_FLOAT(item->style->opacity.value)));
GSList *l = g_slist_reverse(group->childList(false));
while (l) {
- SPObject *o = SP_OBJECT (l->data);
- if (SP_IS_ITEM(o)) {
- renderer->renderItem (ctx, SP_ITEM (o));
+ SPObject *o = reinterpret_cast<SPObject *>(l->data);
+ SPItem *item = dynamic_cast<SPItem *>(o);
+ if (item) {
+ renderer->renderItem(ctx, item);
}
l = g_slist_remove (l, o);
}
}
-static void sp_use_render(SPItem *item, CairoRenderContext *ctx)
+static void sp_use_render(SPUse *use, CairoRenderContext *ctx)
{
bool translated = false;
- SPUse *use = SP_USE(item);
CairoRenderer *renderer = ctx->getRenderer();
if ((use->x._set && use->x.computed != 0) || (use->y._set && use->y.computed != 0)) {
@@ -320,8 +317,8 @@ static void sp_use_render(SPItem *item, CairoRenderContext *ctx)
translated = true;
}
- if (use->child && SP_IS_ITEM(use->child)) {
- renderer->renderItem(ctx, SP_ITEM(use->child));
+ if (use->child) {
+ renderer->renderItem(ctx, use->child);
}
if (translated) {
@@ -329,30 +326,27 @@ static void sp_use_render(SPItem *item, CairoRenderContext *ctx)
}
}
-static void sp_text_render(SPItem *item, CairoRenderContext *ctx)
+static void sp_text_render(SPText *text, CairoRenderContext *ctx)
{
- SPText *group = SP_TEXT (item);
- group->layout.showGlyphs(ctx);
+ text->layout.showGlyphs(ctx);
}
-static void sp_flowtext_render(SPItem *item, CairoRenderContext *ctx)
+static void sp_flowtext_render(SPFlowtext *flowtext, CairoRenderContext *ctx)
{
- SPFlowtext *group = SP_FLOWTEXT(item);
- group->layout.showGlyphs(ctx);
+ flowtext->layout.showGlyphs(ctx);
}
-static void sp_image_render(SPItem *item, CairoRenderContext *ctx)
+static void sp_image_render(SPImage *image, CairoRenderContext *ctx)
{
- SPImage *image;
- int w, h;
-
- image = SP_IMAGE (item);
-
- if (!image->pixbuf) return;
- if ((image->width.computed <= 0.0) || (image->height.computed <= 0.0)) return;
+ if (!image->pixbuf) {
+ return;
+ }
+ if ((image->width.computed <= 0.0) || (image->height.computed <= 0.0)) {
+ return;
+ }
- w = image->pixbuf->width();
- h = image->pixbuf->height();
+ int w = image->pixbuf->width();
+ int h = image->pixbuf->height();
double x = image->x.computed;
double y = image->y.computed;
@@ -372,12 +366,11 @@ static void sp_image_render(SPItem *item, CairoRenderContext *ctx)
Geom::Scale s(width / (double)w, height / (double)h);
Geom::Affine t(s * tp);
- ctx->renderImage (image->pixbuf, t, item->style);
+ ctx->renderImage(image->pixbuf, t, image->style);
}
-static void sp_symbol_render(SPItem *item, CairoRenderContext *ctx)
+static void sp_symbol_render(SPSymbol *symbol, CairoRenderContext *ctx)
{
- SPSymbol *symbol = SP_SYMBOL(item);
if (!symbol->cloned) {
return;
}
@@ -412,7 +405,7 @@ static void sp_symbol_render(SPItem *item, CairoRenderContext *ctx)
ctx->transform(vb2user);
}
- sp_group_render(item, ctx);
+ sp_group_render(symbol, ctx);
ctx->popState();
}
@@ -524,34 +517,56 @@ static void sp_item_invoke_render(SPItem *item, CairoRenderContext *ctx)
SPStyle* style = item->style;
if((ctx->getFilterToBitmap() == TRUE) && (style->filter.set != 0)) {
- return sp_asbitmap_render(item, ctx);
+ sp_asbitmap_render(item, ctx);
}
- if (SP_IS_ROOT(item)) {
+ SPRoot *root = dynamic_cast<SPRoot *>(item);
+ if (root) {
TRACE(("root\n"));
- return sp_root_render(SP_ROOT(item), ctx);
- } else if (SP_IS_SYMBOL(item)) {
- TRACE(("symbol\n"));
- return sp_symbol_render(item, ctx);
- } else if (SP_IS_GROUP(item)) {
- TRACE(("group\n"));
- return sp_group_render(item, ctx);
- } else if (SP_IS_SHAPE(item)) {
- TRACE(("shape\n"));
- return sp_shape_render(item, ctx);
- } else if (SP_IS_USE(item)) {
- TRACE(("use begin---\n"));
- sp_use_render(item, ctx);
- TRACE(("---use end\n"));
- } else if (SP_IS_TEXT(item)) {
- TRACE(("text\n"));
- return sp_text_render(item, ctx);
- } else if (SP_IS_FLOWTEXT(item)) {
- TRACE(("flowtext\n"));
- return sp_flowtext_render(item, ctx);
- } else if (SP_IS_IMAGE(item)) {
- TRACE(("image\n"));
- return sp_image_render(item, ctx);
+ sp_root_render(root, ctx);
+ } else {
+ SPSymbol *symbol = dynamic_cast<SPSymbol *>(item);
+ if (symbol) {
+ TRACE(("symbol\n"));
+ sp_symbol_render(symbol, ctx);
+ } else {
+ SPGroup *group = dynamic_cast<SPGroup *>(item);
+ if (group) {
+ TRACE(("group\n"));
+ sp_group_render(group, ctx);
+ } else {
+ SPShape *shape = dynamic_cast<SPShape *>(item);
+ if (shape) {
+ TRACE(("shape\n"));
+ sp_shape_render(shape, ctx);
+ } else {
+ SPUse *use = dynamic_cast<SPUse *>(item);
+ if (use) {
+ TRACE(("use begin---\n"));
+ sp_use_render(use, ctx);
+ TRACE(("---use end\n"));
+ } else {
+ SPText *text = dynamic_cast<SPText *>(item);
+ if (text) {
+ TRACE(("text\n"));
+ sp_text_render(text, ctx);
+ } else {
+ SPFlowtext *flowtext = dynamic_cast<SPFlowtext *>(item);
+ if (flowtext) {
+ TRACE(("flowtext\n"));
+ sp_flowtext_render(flowtext, ctx);
+ } else {
+ SPImage *image = dynamic_cast<SPImage *>(item);
+ if (image) {
+ TRACE(("image\n"));
+ sp_image_render(image, ctx);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
}
}
@@ -571,8 +586,9 @@ CairoRenderer::setStateForItem(CairoRenderContext *ctx, SPItem const *item)
// This is so because we use the image's/(flow)text's transform for positioning
// instead of explicitly specifying it and letting the renderer do the
// transformation before rendering the item.
- if (SP_IS_TEXT(item) || SP_IS_FLOWTEXT(item) || SP_IS_IMAGE(item))
+ if (dynamic_cast<SPText const *>(item) || dynamic_cast<SPFlowtext const *>(item) || dynamic_cast<SPImage const *>(item)) {
state->parent_has_userspace = TRUE;
+ }
TRACE(("setStateForItem opacity: %f\n", state->opacity));
}
@@ -700,8 +716,8 @@ CairoRenderer::applyClipPath(CairoRenderContext *ctx, SPClipPath const *cp)
TRACE(("BEGIN clip\n"));
SPObject const *co = cp;
for ( SPObject const *child = co->firstChild() ; child; child = child->getNext() ) {
- if (SP_IS_ITEM(child)) {
- SPItem const *item = SP_ITEM(child);
+ SPItem const *item = dynamic_cast<SPItem const *>(child);
+ if (item) {
// combine transform of the item in clippath and the item using clippath:
Geom::Affine tempmat = item->transform * ctx->getCurrentState()->item_transform;
@@ -759,8 +775,8 @@ CairoRenderer::applyMask(CairoRenderContext *ctx, SPMask const *mask)
TRACE(("BEGIN mask\n"));
SPObject const *co = mask;
for ( SPObject const *child = co->firstChild() ; child; child = child->getNext() ) {
- if (SP_IS_ITEM(child)) {
- SPItem const *item = SP_ITEM(child);
+ SPItem const *item = dynamic_cast<SPItem const *>(child);
+ if (item) {
// TODO fix const correctness:
renderItem(ctx, const_cast<SPItem*>(item));
}
diff --git a/src/extension/internal/latex-text-renderer.cpp b/src/extension/internal/latex-text-renderer.cpp
index 398c9f061..ab0733848 100644
--- a/src/extension/internal/latex-text-renderer.cpp
+++ b/src/extension/internal/latex-text-renderer.cpp
@@ -66,7 +66,8 @@ latex_render_document_text_to_file( SPDocument *doc, gchar const *filename,
bool pageBoundingBox = true;
if (exportId && strcmp(exportId, "")) {
// we want to export the given item only
- base = SP_ITEM(doc->getObjectById(exportId));
+ base = dynamic_cast<SPItem *>(doc->getObjectById(exportId));
+ g_assert(base != NULL);
pageBoundingBox = exportCanvas;
}
else {
@@ -225,26 +226,22 @@ LaTeXTextRenderer::writePostamble()
fprintf(_stream, "%s", postamble);
}
-void
-LaTeXTextRenderer::sp_group_render(SPItem *item)
+void LaTeXTextRenderer::sp_group_render(SPGroup *group)
{
- SPGroup *group = SP_GROUP(item);
-
GSList *l = g_slist_reverse(group->childList(false));
while (l) {
- SPObject *o = SP_OBJECT (l->data);
- if (SP_IS_ITEM(o)) {
- renderItem (SP_ITEM (o));
+ SPObject *o = reinterpret_cast<SPObject *>(l->data);
+ SPItem *item = dynamic_cast<SPItem *>(o);
+ if (item) {
+ renderItem(item);
}
l = g_slist_remove (l, o);
}
}
-void
-LaTeXTextRenderer::sp_use_render(SPItem *item)
+void LaTeXTextRenderer::sp_use_render(SPUse *use)
{
bool translated = false;
- SPUse *use = SP_USE(item);
if ((use->x._set && use->x.computed != 0) || (use->y._set && use->y.computed != 0)) {
Geom::Affine tp(Geom::Translate(use->x.computed, use->y.computed));
@@ -252,8 +249,9 @@ LaTeXTextRenderer::sp_use_render(SPItem *item)
translated = true;
}
- if (use->child && SP_IS_ITEM(use->child)) {
- renderItem(SP_ITEM(use->child));
+ SPItem *childItem = dynamic_cast<SPItem *>(use->child);
+ if (childItem) {
+ renderItem(childItem);
}
if (translated) {
@@ -261,16 +259,14 @@ LaTeXTextRenderer::sp_use_render(SPItem *item)
}
}
-void
-LaTeXTextRenderer::sp_text_render(SPItem *item)
+void LaTeXTextRenderer::sp_text_render(SPText *textobj)
{
// Only PDFLaTeX supports importing a single page of a graphics file,
// so only PDF backend gets interleaved text/graphics
if (_pdflatex && _omittext_state == GRAPHIC_ON_TOP)
_omittext_state = NEW_PAGE_ON_GRAPHIC;
- SPText *textobj = SP_TEXT (item);
- SPStyle *style = item->style;
+ SPStyle *style = textobj->style;
// get position and alignment
// Align vertically on the baseline of the font (retreived from the anchor point)
@@ -312,7 +308,7 @@ LaTeXTextRenderer::sp_text_render(SPItem *item)
}
// get rotation
- Geom::Affine i2doc = item->i2doc_affine();
+ Geom::Affine i2doc = textobj->i2doc_affine();
Geom::Affine wotransl = i2doc.withoutTranslation();
double degrees = -180/M_PI * Geom::atan2(wotransl.xAxis());
bool has_rotation = !Geom::are_near(degrees,0.);
@@ -336,11 +332,11 @@ LaTeXTextRenderer::sp_text_render(SPItem *item)
// Walk through all spans in the text object.
// Write span strings to LaTeX, associated with font weight and style.
- Inkscape::Text::Layout const &layout = *(te_get_layout (item));
+ Inkscape::Text::Layout const &layout = *(te_get_layout (textobj));
for (Inkscape::Text::Layout::iterator li = layout.begin(), le = layout.end();
li != le; li.nextStartOfSpan())
{
- SPStyle const &spanstyle = *(sp_te_style_at_position (item, li));
+ SPStyle const &spanstyle = *(sp_te_style_at_position (textobj, li));
bool is_bold = false, is_italic = false, is_oblique = false;
if (spanstyle.font_weight.computed == SP_CSS_FONT_WEIGHT_500 ||
@@ -367,7 +363,7 @@ LaTeXTextRenderer::sp_text_render(SPItem *item)
Inkscape::Text::Layout::iterator ln = li;
ln.nextStartOfSpan();
- Glib::ustring uspanstr = sp_te_get_string_multiline (item, li, ln);
+ Glib::ustring uspanstr = sp_te_get_string_multiline (textobj, li, ln);
const gchar *spanstr = uspanstr.c_str();
if (!spanstr) {
continue;
@@ -394,8 +390,7 @@ LaTeXTextRenderer::sp_text_render(SPItem *item)
fprintf(_stream, "%s", os.str().c_str());
}
-void
-LaTeXTextRenderer::sp_flowtext_render(SPItem * item)
+void LaTeXTextRenderer::sp_flowtext_render(SPFlowtext *flowtext)
{
/*
Flowtext is possible by using a minipage! :)
@@ -407,16 +402,15 @@ Flowing in rectangle is possible, not in arb shape.
if (_pdflatex && _omittext_state == GRAPHIC_ON_TOP)
_omittext_state = NEW_PAGE_ON_GRAPHIC;
- SPFlowtext *flowtext = SP_FLOWTEXT(item);
- SPStyle *style = item->style;
+ SPStyle *style = flowtext->style;
SPItem *frame_item = flowtext->get_frame(NULL);
- if (!frame_item || !SP_IS_RECT(frame_item)) {
+ SPRect *frame = dynamic_cast<SPRect *>(frame_item);
+ if (!frame_item || !frame) {
g_warning("LaTeX export: non-rectangular flowed text shapes are not supported, skipping text.");
return; // don't know how to handle non-rect frames yet. is quite uncommon for latex users i think
}
- SPRect *frame = SP_RECT(frame_item);
Geom::Rect framebox = frame->getRect() * transform();
// get position and alignment
@@ -460,7 +454,7 @@ Flowing in rectangle is possible, not in arb shape.
}
// get rotation
- Geom::Affine i2doc = item->i2doc_affine();
+ Geom::Affine i2doc = flowtext->i2doc_affine();
Geom::Affine wotransl = i2doc.withoutTranslation();
double degrees = -180/M_PI * Geom::atan2(wotransl.xAxis());
bool has_rotation = !Geom::are_near(degrees,0.);
@@ -485,11 +479,11 @@ Flowing in rectangle is possible, not in arb shape.
// Walk through all spans in the text object.
// Write span strings to LaTeX, associated with font weight and style.
- Inkscape::Text::Layout const &layout = *(te_get_layout (item));
+ Inkscape::Text::Layout const &layout = *(te_get_layout(flowtext));
for (Inkscape::Text::Layout::iterator li = layout.begin(), le = layout.end();
li != le; li.nextStartOfSpan())
{
- SPStyle const &spanstyle = *(sp_te_style_at_position (item, li));
+ SPStyle const &spanstyle = *(sp_te_style_at_position(flowtext, li));
bool is_bold = false, is_italic = false, is_oblique = false;
if (spanstyle.font_weight.computed == SP_CSS_FONT_WEIGHT_500 ||
@@ -516,7 +510,7 @@ Flowing in rectangle is possible, not in arb shape.
Inkscape::Text::Layout::iterator ln = li;
ln.nextStartOfSpan();
- Glib::ustring uspanstr = sp_te_get_string_multiline (item, li, ln);
+ Glib::ustring uspanstr = sp_te_get_string_multiline(flowtext, li, ln);
const gchar *spanstr = uspanstr.c_str();
if (!spanstr) {
continue;
@@ -558,22 +552,36 @@ LaTeXTextRenderer::sp_item_invoke_render(SPItem *item)
return;
}
- if (SP_IS_ROOT(item)) {
- return sp_root_render(SP_ROOT(item));
- } else if (SP_IS_GROUP(item)) {
- return sp_group_render(item);
- } else if (SP_IS_USE(item)) {
- sp_use_render(item);
- } else if (SP_IS_TEXT(item)) {
- return sp_text_render(item);
- } else if (SP_IS_FLOWTEXT(item)) {
- return sp_flowtext_render(item);
+ SPRoot *root = dynamic_cast<SPRoot *>(item);
+ if (root) {
+ sp_root_render(root);
} else {
- // Only PDFLaTeX supports importing a single page of a graphics file,
- // so only PDF backend gets interleaved text/graphics
- if (_pdflatex && (_omittext_state == EMPTY || _omittext_state == NEW_PAGE_ON_GRAPHIC))
- writeGraphicPage();
- _omittext_state = GRAPHIC_ON_TOP;
+ SPGroup *group = dynamic_cast<SPGroup *>(item);
+ if (group) {
+ sp_group_render(group);
+ } else {
+ SPUse *use = dynamic_cast<SPUse *>(item);
+ if (use) {
+ sp_use_render(use);
+ } else {
+ SPText *text = dynamic_cast<SPText *>(item);
+ if (text) {
+ sp_text_render(text);
+ } else {
+ SPFlowtext *flowtext = dynamic_cast<SPFlowtext *>(item);
+ if (flowtext) {
+ sp_flowtext_render(flowtext);
+ } else {
+ // Only PDFLaTeX supports importing a single page of a graphics file,
+ // so only PDF backend gets interleaved text/graphics
+ if (_pdflatex && (_omittext_state == EMPTY || _omittext_state == NEW_PAGE_ON_GRAPHIC)) {
+ writeGraphicPage();
+ }
+ _omittext_state = GRAPHIC_ON_TOP;
+ }
+ }
+ }
+ }
}
}
diff --git a/src/extension/internal/latex-text-renderer.h b/src/extension/internal/latex-text-renderer.h
index 77d12bc61..b9563b53b 100644
--- a/src/extension/internal/latex-text-renderer.h
+++ b/src/extension/internal/latex-text-renderer.h
@@ -23,6 +23,10 @@
class SPItem;
class SPRoot;
+class SPGroup;
+class SPUse;
+class SPText;
+class SPFlowtext;
namespace Inkscape {
namespace Extension {
@@ -73,10 +77,10 @@ protected:
void sp_item_invoke_render(SPItem *item);
void sp_root_render(SPRoot *item);
- void sp_group_render(SPItem *item);
- void sp_use_render(SPItem *item);
- void sp_text_render(SPItem *item);
- void sp_flowtext_render(SPItem *item);
+ void sp_group_render(SPGroup *group);
+ void sp_use_render(SPUse *use);
+ void sp_text_render(SPText *text);
+ void sp_flowtext_render(SPFlowtext *flowtext);
};
} /* namespace Internal */