summary | shortlog | log | commit | commitdiff | tree
raw | patch | inline | side by side (parent: 637b6ca)
raw | patch | inline | side by side (parent: 637b6ca)
author | tavmjong-free <tavmjong@free.fr> | |
Fri, 4 Jun 2010 19:41:52 +0000 (21:41 +0200) | ||
committer | tavmjong-free <tavmjong@free.fr> | |
Fri, 4 Jun 2010 19:41:52 +0000 (21:41 +0200) |
Add superscript and subscript support to Text toolbar.
Missing icons for superscript and subscript.
Known bug: adding a character to a superscript or subscript text
string resets baseline-shift attribute.
Missing icons for superscript and subscript.
Known bug: adding a character to a superscript or subscript text
string resets baseline-shift attribute.
diff --git a/src/desktop-style.cpp b/src/desktop-style.cpp
index 2225be5ee6447cfc94c44939a97b67e711223c1a..2c2a99aee6b76e5fccb573259a47c96fa8030719 100644 (file)
--- a/src/desktop-style.cpp
+++ b/src/desktop-style.cpp
}
}
+/**
+ * Write to style_res the baseline numbers.
+ */
+int
+objects_query_baselines (GSList *objects, SPStyle *style_res)
+{
+ bool different = false;
+
+ // Only baseline-shift at the moment
+ // We will return:
+ // If baseline-shift is same for all objects:
+ // The full baseline-shift data (used for subscripts and superscripts)
+ // If baseline-shift is different:
+ // The average baseline-shift (not implemented at the moment as this is complicated June 2010)
+ SPIBaselineShift old;
+ old.value = 0.0;
+ old.computed = 0.0;
+
+ // double baselineshift = 0.0;
+ bool set = false;
+
+ int texts = 0;
+
+ for (GSList const *i = objects; i != NULL; i = i->next) {
+ SPObject *obj = SP_OBJECT (i->data);
+
+ if (!SP_IS_TEXT(obj) && !SP_IS_FLOWTEXT(obj)
+ && !SP_IS_TSPAN(obj) && !SP_IS_TREF(obj) && !SP_IS_TEXTPATH(obj)
+ && !SP_IS_FLOWDIV(obj) && !SP_IS_FLOWPARA(obj) && !SP_IS_FLOWTSPAN(obj))
+ continue;
+
+ SPStyle *style = SP_OBJECT_STYLE (obj);
+ if (!style) continue;
+
+ texts ++;
+
+ SPIBaselineShift current;
+ if(style->baseline_shift.set) {
+
+ current.set = style->baseline_shift.set;
+ current.inherit = style->baseline_shift.inherit;
+ current.type = style->baseline_shift.type;
+ current.literal = style->baseline_shift.literal;
+ current.value = style->baseline_shift.value;
+ current.computed = style->baseline_shift.computed;
+
+ if( set ) {
+ if( current.set != old.set ||
+ current.inherit != old.inherit ||
+ current.type != old.type ||
+ current.literal != old.literal ||
+ current.value != old.value ||
+ current.computed != old.computed ) {
+ // Maybe this needs to be better thought out.
+ different = true;
+ }
+ }
+
+ set = true;
+
+ old.set = current.set;
+ old.inherit = current.inherit;
+ old.type = current.type;
+ old.literal = current.literal;
+ old.value = current.value;
+ old.computed = current.computed;
+ }
+ }
+
+ if (different || !set ) {
+ style_res->baseline_shift.set = false;
+ style_res->baseline_shift.computed = 0.0;
+ } else {
+ style_res->baseline_shift.set = old.set;
+ style_res->baseline_shift.inherit = old.inherit;
+ style_res->baseline_shift.type = old.type;
+ style_res->baseline_shift.literal = old.literal;
+ style_res->baseline_shift.value = old.value;
+ style_res->baseline_shift.computed = old.computed;
+ }
+
+ if (texts == 0 || !set)
+ return QUERY_STYLE_NOTHING;
+
+ if (texts > 1) {
+ if (different) {
+ return QUERY_STYLE_MULTIPLE_DIFFERENT;
+ } else {
+ return QUERY_STYLE_MULTIPLE_SAME;
+ }
+ } else {
+ return QUERY_STYLE_SINGLE;
+ }
+}
+
/**
* Write to style_res the average font family of objects.
*/
return objects_query_fontstyle (list, style);
} else if (property == QUERY_STYLE_PROPERTY_FONTNUMBERS) {
return objects_query_fontnumbers (list, style);
+ } else if (property == QUERY_STYLE_PROPERTY_BASELINES) {
+ return objects_query_baselines (list, style);
} else if (property == QUERY_STYLE_PROPERTY_BLEND) {
return objects_query_blend (list, style);
diff --git a/src/desktop-style.h b/src/desktop-style.h
index 40461da723cea5b8909f0855db1538fad0f0a4bb..e1ca5b3e7db4009aae1b3d80c98a95d24764d154 100644 (file)
--- a/src/desktop-style.h
+++ b/src/desktop-style.h
QUERY_STYLE_PROPERTY_FONTFAMILY, // font-family
QUERY_STYLE_PROPERTY_FONTSTYLE, // font style
QUERY_STYLE_PROPERTY_FONTNUMBERS, // size, spacings
+ QUERY_STYLE_PROPERTY_BASELINES, // baseline-shift
QUERY_STYLE_PROPERTY_MASTEROPACITY, // opacity
QUERY_STYLE_PROPERTY_BLEND, // blend
QUERY_STYLE_PROPERTY_BLUR // blur
index b958e899dca6c713db228cbc687c6f590ab07dd9..bdf7003464d58470919a2c9309f53259c7a212f4 100644 (file)
SetGraphicsMode(daddy->hScreenDC, GM_COMPATIBLE);
SelectObject(daddy->hScreenDC,theFace);
#else
- theFace=pango_ft2_font_get_face(pFont);
+ theFace=pango_ft2_font_get_face(pFont); // Deprecated, use pango_fc_font_lock_face() instead
if ( theFace ) {
FT_Select_Charmap(theFace,ft_encoding_unicode) && FT_Select_Charmap(theFace,ft_encoding_symbol);
}
ascent=fabs(otm.otmAscent*scale);
descent=fabs(otm.otmDescent*scale);
leading=fabs(otm.otmLineGap*scale);
+ //otmSubscriptSize, otmSubscriptOffset, otmSuperscriptSize, otmSuperscriptOffset,
#else
if ( theFace->units_per_EM == 0 ) {
return false; // bitmap font
index cad2f9b19996a598e3dda61f6498c4f34d6b0934..192596ecf2b96d2a04767b1133880066c0f471e9 100644 (file)
unsigned input_index; /// index into Layout::_input_stream
Glib::ustring::const_iterator input_stream_first_character;
double font_size;
- LineHeight line_height;
+ LineHeight line_height; /// This is not the CSS line-height attribute!
double line_height_multiplier; /// calculated from the font-height css property
+ double baseline_shift; /// calculated from the baseline-shift css property
unsigned text_bytes;
unsigned char_index_in_para; /// the index of the first character in this span in the paragraph, for looking up char_attributes
SVGLength x, y, dx, dy, rotate; // these are reoriented copies of the <tspan> attributes. We change span when we encounter one.
new_span.in_chunk = _flow._chunks.size() - 1;
new_span.line_height = unbroken_span.line_height;
new_span.in_input_stream_item = unbroken_span.input_index;
- new_span.baseline_shift = _y_offset;
+ new_span.baseline_shift = 0.0;
new_span.block_progression = _block_progression;
if ((_flow._input_stream[unbroken_span.input_index]->Type() == TEXT_SOURCE) && (new_span.font = para.pango_items[unbroken_span.pango_item_index].font))
{
if (_block_progression == LEFT_TO_RIGHT || _block_progression == RIGHT_TO_LEFT) {
new_glyph.x = x + unbroken_span.glyph_string->glyphs[glyph_index].geometry.x_offset * font_size_multiplier + new_span.line_height.ascent;
- new_glyph.y = _y_offset + (unbroken_span.glyph_string->glyphs[glyph_index].geometry.y_offset - unbroken_span.glyph_string->glyphs[glyph_index].geometry.width * 0.5) * font_size_multiplier;
+ new_glyph.y = _y_offset -
+ unbroken_span.baseline_shift +
+ (unbroken_span.glyph_string->glyphs[glyph_index].geometry.y_offset -
+ unbroken_span.glyph_string->glyphs[glyph_index].geometry.width * 0.5) * font_size_multiplier;
new_glyph.width = new_span.font_size * para.pango_items[unbroken_span.pango_item_index].font->Advance(unbroken_span.glyph_string->glyphs[glyph_index].glyph, true);
} else {
new_glyph.x = x + unbroken_span.glyph_string->glyphs[glyph_index].geometry.x_offset * font_size_multiplier;
- new_glyph.y = _y_offset + unbroken_span.glyph_string->glyphs[glyph_index].geometry.y_offset * font_size_multiplier;
+ new_glyph.y = _y_offset -
+ unbroken_span.baseline_shift +
+ unbroken_span.glyph_string->glyphs[glyph_index].geometry.y_offset * font_size_multiplier;
new_glyph.width = unbroken_span.glyph_string->glyphs[glyph_index].geometry.width * font_size_multiplier;
if ((new_glyph.width == 0) && (para.pango_items[unbroken_span.pango_item_index].font))
new_glyph.width = new_span.font_size * para.pango_items[unbroken_span.pango_item_index].font->Advance(unbroken_span.glyph_string->glyphs[glyph_index].glyph, false);
@@ -984,6 +990,7 @@ void Layout::Calculator::_computeFontLineHeight(font_instance *font, double font
*line_height_multiplier = LINE_HEIGHT_NORMAL * font_size / line_height->total();
}
+
/**
* Split the paragraph into spans. Also call pango_shape() on them.
*
}
new_span.pango_item_index = pango_item_index;
_computeFontLineHeight(para->pango_items[pango_item_index].font, new_span.font_size, text_source->style, &new_span.line_height, &new_span.line_height_multiplier);
+
+ // At some point we may want to calculate baseline_shift here (to take advantage
+ // of otm features like superscript baseline), but for now we use style baseline_shift.
+ new_span.baseline_shift = text_source->style->baseline_shift.computed;
+
// TODO: metrics for vertical text
TRACE(("add text span %d \"%s\"\n", para->unbroken_spans.size(), text_source->text->raw().substr(span_start_byte_in_source, new_span.text_bytes).c_str()));
TRACE((" %d glyphs\n", new_span.glyph_string->num_glyphs));
diff --git a/src/sp-text.cpp b/src/sp-text.cpp
index 0f21b59d19a237b0129942442e89db47661d1cbf..bae625f5837317903e8201a38a3418361d04ca1f 100644 (file)
--- a/src/sp-text.cpp
+++ b/src/sp-text.cpp
@@ -528,6 +528,8 @@ unsigned SPText::_buildLayoutInput(SPObject *root, Inkscape::Text::Layout::Optio
}
else if (SP_IS_TSPAN(root)) {
SPTSpan *tspan = SP_TSPAN(root);
+ // x, y attributes are stripped from some tspans as we do our own line layout
+ // This should be checked carefully, as it can undo line layout in imported SVG files.
bool use_xy = !in_textpath && (tspan->role == SP_TSPAN_ROLE_UNSPECIFIED || !tspan->attributes.singleXYCoordinates());
tspan->attributes.mergeInto(&optional_attrs, parent_optional_attrs, parent_attrs_offset, use_xy, true);
}
diff --git a/src/style.cpp b/src/style.cpp
index a05cef252c1d789d0e0a7b88d813c66c159df1f4..f2686287184228017fadde3950814b4bd8024321 100644 (file)
--- a/src/style.cpp
+++ b/src/style.cpp
@@ -88,11 +88,13 @@ static void sp_style_read_itextdecoration(SPITextDecoration *val, gchar const *s
static void sp_style_read_icolor(SPIPaint *paint, gchar const *str, SPStyle *style, SPDocument *document);
static void sp_style_read_ipaint(SPIPaint *paint, gchar const *str, SPStyle *style, SPDocument *document);
static void sp_style_read_ifontsize(SPIFontSize *val, gchar const *str);
+static void sp_style_read_ibaselineshift(SPIBaselineShift *val, gchar const *str);
static void sp_style_read_ifilter(gchar const *str, SPStyle *style, SPDocument *document);
static void sp_style_read_penum(SPIEnum *val, Inkscape::XML::Node *repr, gchar const *key, SPStyleEnum const *dict, bool can_explicitly_inherit);
static void sp_style_read_plength(SPILength *val, Inkscape::XML::Node *repr, gchar const *key);
static void sp_style_read_pfontsize(SPIFontSize *val, Inkscape::XML::Node *repr, gchar const *key);
+static void sp_style_read_pbaselineshift(SPIBaselineShift *val, Inkscape::XML::Node *repr, gchar const *key);
static void sp_style_read_pfloat(SPIFloat *val, Inkscape::XML::Node *repr, gchar const *key);
static gint sp_style_write_ifloat(gchar *p, gint len, gchar const *key, SPIFloat const *val, SPIFloat const *base, guint flags);
@@ -102,6 +104,7 @@ static gint sp_style_write_istring(gchar *p, gint len, gchar const *key, SPIStri
static gint sp_style_write_ilength(gchar *p, gint len, gchar const *key, SPILength const *val, SPILength const *base, guint flags);
static gint sp_style_write_ipaint(gchar *b, gint len, gchar const *key, SPIPaint const *paint, SPIPaint const *base, guint flags);
static gint sp_style_write_ifontsize(gchar *p, gint len, gchar const *key, SPIFontSize const *val, SPIFontSize const *base, guint flags);
+static gint sp_style_write_ibaselineshift(gchar *p, gint len, gchar const *key, SPIBaselineShift const *val, SPIBaselineShift const *base, guint flags);
static gint sp_style_write_ilengthornormal(gchar *p, gint const len, gchar const *const key, SPILengthOrNormal const *const val, SPILengthOrNormal const *const base, guint const flags);
static gint sp_style_write_itextdecoration(gchar *p, gint const len, gchar const *const key, SPITextDecoration const *const val, SPITextDecoration const *const base, guint const flags);
static gint sp_style_write_ifilter(gchar *b, gint len, gchar const *key, SPIFilter const *filter, SPIFilter const *base, guint flags);
#define SPS_READ_IFONTSIZE_IF_UNSET(v,s) if (!(v)->set) {sp_style_read_ifontsize((v), (s));}
#define SPS_READ_PFONTSIZE_IF_UNSET(v,r,k) if (!(v)->set) {sp_style_read_pfontsize((v), (r), (k));}
+#define SPS_READ_IBASELINE_SHIFT_IF_UNSET(v,s) if (!(v)->set) {sp_style_read_ibaselineshift((v), (s));}
+#define SPS_READ_PBASELINE_SHIFT_IF_UNSET(v,r,k) if (!(v)->set) {sp_style_read_pbaselineshift((v), (r), (k));}
+
static void sp_style_merge_from_object_stylesheet(SPStyle *, SPObject const *);
struct SPStyleEnum {
{NULL, -1}
};
+static SPStyleEnum const enum_baseline_shift[] = {
+ {"baseline", SP_CSS_BASELINE_SHIFT_BASELINE},
+ {"sub", SP_CSS_BASELINE_SHIFT_SUB},
+ {"super", SP_CSS_BASELINE_SHIFT_SUPER},
+ {NULL, -1}
+};
+
static SPStyleEnum const enum_visibility[] = {
{"hidden", SP_CSS_VISIBILITY_HIDDEN},
{"collapse", SP_CSS_VISIBILITY_COLLAPSE},
enum_writing_mode, true);
SPS_READ_PENUM_IF_UNSET(&style->text_anchor, repr, "text-anchor",
enum_text_anchor, true);
+ SPS_READ_PBASELINE_SHIFT_IF_UNSET(&style->baseline_shift, repr, "baseline-shift");
/* opacity */
if (!style->opacity.set) {
case SP_PROP_TEXT_ANCHOR:
SPS_READ_IENUM_IF_UNSET(&style->text_anchor, val, enum_text_anchor, true);
break;
+ case SP_PROP_BASELINE_SHIFT:
+ SPS_READ_IBASELINE_SHIFT_IF_UNSET(&style->baseline_shift, val);
+ break;
/* Text (unimplemented) */
case SP_PROP_TEXT_RENDERING: {
/* Ignore the hint. */
case SP_PROP_ALIGNMENT_BASELINE:
g_warning("Unimplemented style property SP_PROP_ALIGNMENT_BASELINE: value: %s", val);
break;
- case SP_PROP_BASELINE_SHIFT:
- g_warning("Unimplemented style property SP_PROP_BASELINE_SHIFT: value: %s", val);
- break;
case SP_PROP_DOMINANT_BASELINE:
g_warning("Unimplemented style property SP_PROP_DOMINANT_BASELINE: value: %s", val);
break;
@@ -1342,6 +1356,48 @@ sp_style_merge_font_size_from_parent(SPIFontSize &child, SPIFontSize const &pare
}
}
+// Some shifts are defined relative to parent.
+static void
+sp_style_merge_baseline_shift_from_parent(SPIBaselineShift &child, SPIBaselineShift const &parent,
+ SPIFontSize const &pfont_size)
+{
+ /* 'baseline-shift' */
+ if (!child.set || child.inherit) {
+ /* Inherit the computed value. Reference: http://www.w3.org/TR/SVG11/styling.html#Inheritance */
+ child.computed = parent.computed; // Does this make sense (applying a shift a second time)?
+ } else if (child.type == SP_BASELINE_SHIFT_LITERAL) {
+ if( child.literal == SP_CSS_BASELINE_SHIFT_BASELINE ) {
+ child.computed = 0; // No change
+ } else if (child.literal == SP_CSS_BASELINE_SHIFT_SUB ) {
+ // Should use subscript position from font relative to alphabetic baseline
+ // In mean time use values from OpenOffice and Adobe
+ child.computed = -0.33 * pfont_size.computed;
+ } else if (child.literal == SP_CSS_BASELINE_SHIFT_SUPER ) {
+ // Should use superscript position from font relative to alphabetic baseline
+ // In mean time use values from OpenOffice and Adobe
+ child.computed = 0.33 * pfont_size.computed;
+ } else {
+ /* Illegal value */
+ }
+ } else if (child.type == SP_BASELINE_SHIFT_PERCENTAGE) {
+ // Percentage for baseline shift is relative to computed "line-height"
+ // which is just font-size (see SVG1.1 'font').
+ child.computed = pfont_size.computed * child.value;
+ } else if (child.type == SP_BASELINE_SHIFT_LENGTH) {
+ switch (child.unit) {
+ case SP_CSS_UNIT_EM:
+ child.computed = child.value * pfont_size.computed;
+ break;
+ case SP_CSS_UNIT_EX:
+ child.computed = child.value * 0.5 * pfont_size.computed;
+ break;
+ default:
+ /* No change */
+ break;
+ }
+ }
+}
+
/**
* Sets computed values in \a style, which may involve inheriting from (or in some other way
* calculating from) corresponding computed values of \a parent.
@@ -1483,6 +1539,10 @@ sp_style_merge_from_parent(SPStyle *const style, SPStyle const *const parent)
style->text_anchor.computed = parent->text_anchor.computed;
}
+ /* Baseline Shift... Some shifts are relative to parent. */
+ sp_style_merge_baseline_shift_from_parent(style->baseline_shift, parent->baseline_shift,
+ parent->font_size);
+
if (style->opacity.inherit) {
style->opacity.value = parent->opacity.value;
}
p += sp_style_write_ienum(p, c + BMAX - p, "writing-mode", enum_writing_mode, &style->writing_mode, NULL, flags);
p += sp_style_write_ienum(p, c + BMAX - p, "text-anchor", enum_text_anchor, &style->text_anchor, NULL, flags);
+ p += sp_style_write_ibaselineshift(p, c + BMAX - p, "baseline-shift", &style->baseline_shift, NULL, flags);
+
/// \todo fixme: Per type methods need default flag too (lauris)
p += sp_style_write_ienum(p, c + BMAX - p, "writing-mode", enum_writing_mode, &from->writing_mode, &to->writing_mode, SP_STYLE_FLAG_IFDIFF);
p += sp_style_write_ienum(p, c + BMAX - p, "text-anchor", enum_text_anchor, &from->text_anchor, &to->text_anchor, SP_STYLE_FLAG_IFDIFF);
+ p += sp_style_write_ibaselineshift(p, c + BMAX - p, "baseline-shift", &from->baseline_shift, &to->baseline_shift, SP_STYLE_FLAG_IFDIFF);
/// \todo fixme: Per type methods need default flag too
if (from->opacity.set && from->opacity.value != SP_SCALE24_MAX) {
style->word_spacing.normal = TRUE;
style->word_spacing.value = style->word_spacing.computed = 0.0;
+ style->baseline_shift.set = FALSE;
+ style->baseline_shift.type = SP_BASELINE_SHIFT_LITERAL;
+ style->baseline_shift.unit = SP_CSS_UNIT_NONE;
+ style->baseline_shift.literal = SP_CSS_BASELINE_SHIFT_BASELINE;
+ style->baseline_shift.value = 0.0;
+ style->baseline_shift.computed = 0.0;
+
style->text_transform.set = FALSE;
style->text_transform.value = style->text_transform.computed = SP_CSS_TEXT_TRANSFORM_NONE;
style->writing_mode.set = FALSE;
style->writing_mode.value = style->writing_mode.computed = SP_CSS_WRITING_MODE_LR_TB;
-
style->text_anchor.set = FALSE;
style->text_anchor.value = style->text_anchor.computed = SP_CSS_TEXT_ANCHOR_START;
val->set = TRUE;
val->inherit = TRUE;
} else if ((*str == 'x') || (*str == 's') || (*str == 'm') || (*str == 'l')) {
+ // xx-small, x-small, etc.
for (unsigned i = 0; enum_font_size[i].key; i++) {
if (!strcmp(str, enum_font_size[i].key)) {
val->set = TRUE;
}
+/**
+ * Set SPIBaselineShift object from string.
+ */
+static void
+sp_style_read_ibaselineshift(SPIBaselineShift *val, gchar const *str)
+{
+ if (!strcmp(str, "inherit")) {
+ val->set = TRUE;
+ val->inherit = TRUE;
+ } else if ((*str == 'b') || (*str == 's')) {
+ // baseline or sub or super
+ for (unsigned i = 0; enum_baseline_shift[i].key; i++) {
+ if (!strcmp(str, enum_baseline_shift[i].key)) {
+ val->set = TRUE;
+ val->inherit = FALSE;
+ val->type = SP_BASELINE_SHIFT_LITERAL;
+ val->literal = enum_baseline_shift[i].value;
+ return;
+ }
+ }
+ /* Invalid */
+ return;
+ } else {
+ SPILength length;
+ sp_style_read_ilength(&length, str);
+ val->set = length.set;
+ val->inherit = length.inherit;
+ val->unit = length.unit;
+ val->value = length.value;
+ val->computed = length.computed;
+ if( val->unit == SP_CSS_UNIT_PERCENT ) {
+ val->type = SP_BASELINE_SHIFT_PERCENTAGE;
+ } else {
+ val->type = SP_BASELINE_SHIFT_LENGTH;
+ }
+ return;
+ }
+}
+
/**
* Set SPIFilter object from string.
@@ -3368,6 +3477,19 @@ sp_style_read_pfontsize(SPIFontSize *val, Inkscape::XML::Node *repr, gchar const
}
+/**
+ * Set SPIBaselineShift object from repr attribute.
+ */
+static void
+sp_style_read_pbaselineshift(SPIBaselineShift *val, Inkscape::XML::Node *repr, gchar const *key)
+{
+ gchar const *str = repr->attribute(key);
+ if (str) {
+ sp_style_read_ibaselineshift(val, str);
+ }
+}
+
+
/**
* Set SPIFloat object from repr attribute.
*/
}
+/**
+ *
+ */
+static bool
+sp_baseline_shift_differ(SPIBaselineShift const *const a, SPIBaselineShift const *const b)
+{
+ if (a->type != b->type)
+ return true;
+ if (a->type == SP_BASELINE_SHIFT_LITERAL ) {
+ if (a->literal != b->literal)
+ return true;
+ }
+ if (a->type == SP_BASELINE_SHIFT_LENGTH) {
+ if (a->unit == SP_CSS_UNIT_EM || a->unit == SP_CSS_UNIT_EX ) {
+ if( a->value != b->value )
+ return true;
+ } else {
+ if (a->computed != b->computed)
+ return true;
+ }
+ }
+ if (a->type == SP_BASELINE_SHIFT_PERCENTAGE) {
+ if (a->value != b->value)
+ return true;
+ }
+ return false;
+}
+
+
+/**
+ * Write SPIBaselineShift object into string.
+ */
+static gint
+sp_style_write_ibaselineshift(gchar *p, gint const len, gchar const *key,
+ SPIBaselineShift const *const val, SPIBaselineShift const *const base,
+ guint const flags)
+{
+ if ((flags & SP_STYLE_FLAG_ALWAYS)
+ || ((flags & SP_STYLE_FLAG_IFSET) && val->set)
+ || ((flags & SP_STYLE_FLAG_IFDIFF) && val->set
+ && (!base->set || sp_baseline_shift_differ(val, base))))
+ {
+ if (val->inherit) {
+ return g_snprintf(p, len, "%s:inherit;", key);
+ } else if (val->type == SP_BASELINE_SHIFT_LITERAL) {
+ for (unsigned i = 0; enum_baseline_shift[i].key; i++) {
+ if (enum_baseline_shift[i].value == static_cast< gint > (val->value) ) {
+ return g_snprintf(p, len, "%s:%s;", key, enum_baseline_shift[i].key);
+ }
+ }
+ } else if (val->type == SP_BASELINE_SHIFT_LENGTH) {
+ if( val->unit == SP_CSS_UNIT_EM || val->unit == SP_CSS_UNIT_EX ) {
+ Inkscape::CSSOStringStream os;
+ os << key << ":" << val->value << (val->unit == SP_CSS_UNIT_EM ? "em;" : "ex;");
+ return g_strlcpy(p, os.str().c_str(), len);
+ } else {
+ Inkscape::CSSOStringStream os;
+ os << key << ":" << val->computed << "px;"; // must specify px, see inkscape bug 1221626, mozilla bug 234789
+ return g_strlcpy(p, os.str().c_str(), len);
+ }
+ } else if (val->type == SP_BASELINE_SHIFT_PERCENTAGE) {
+ Inkscape::CSSOStringStream os;
+ os << key << ":" << (val->value * 100.0) << "%;";
+ return g_strlcpy(p, os.str().c_str(), len);
+ }
+ }
+ return 0;
+}
+
+
+
/**
* Write SPIFilter object into string.
*/
sp_repr_css_set_property(css, "kerning", NULL); // not implemented yet
sp_repr_css_set_property(css, "dominant-baseline", NULL); // not implemented yet
sp_repr_css_set_property(css, "alignment-baseline", NULL); // not implemented yet
- sp_repr_css_set_property(css, "baseline-shift", NULL); // not implemented yet
+ sp_repr_css_set_property(css, "baseline-shift", NULL);
return css;
}
diff --git a/src/style.h b/src/style.h
index f1b5ec534cb622263372bb439e22cc174e8c15b4..02ef41bf805b9c01a23e65b64f4bc1fcc4d9a6fe 100644 (file)
--- a/src/style.h
+++ b/src/style.h
class SPILength;
class SPIPaint;
class SPIFontSize;
+class SPIBaselineShift;
/// Float type internal to SPStyle.
struct SPIFloat {
SP_FONT_SIZE_PERCENTAGE
};
+enum {
+ SP_BASELINE_SHIFT_LITERAL,
+ SP_BASELINE_SHIFT_LENGTH,
+ SP_BASELINE_SHIFT_PERCENTAGE
+};
+
#define SP_FONT_SIZE ((1 << 24) - 1)
#define SP_F8_16_TO_FLOAT(v) ((gdouble) (v) / (1 << 16))
float computed;
};
+/// Baseline shift type internal to SPStyle.
+struct SPIBaselineShift {
+ unsigned set : 1;
+ unsigned inherit : 1;
+ unsigned type : 2;
+ unsigned unit : 4;
+ unsigned literal: 2;
+ float value; // Can be negative
+ float computed;
+};
+
/// Text decoration type internal to SPStyle.
struct SPITextDecoration {
unsigned set : 1;
SPIEnum block_progression;
/** Writing mode (css3 text 3.2 and svg1.1 10.7.2) */
SPIEnum writing_mode;
+ /** Baseline shift (svg1.1 10.9.2) */
+ SPIBaselineShift baseline_shift;
/* SVG */
/** Anchor of the text (svg1.1 10.9.1) */
SP_CSS_TEXT_ANCHOR_END
};
+enum SPCSSBaselineShift {
+ SP_CSS_BASELINE_SHIFT_BASELINE,
+ SP_CSS_BASELINE_SHIFT_SUB,
+ SP_CSS_BASELINE_SHIFT_SUPER
+};
+
enum SPVisibility {
SP_CSS_VISIBILITY_HIDDEN,
SP_CSS_VISIBILITY_COLLAPSE,
index f3cfe621d5711df6b74bfaea52a5d7b54a46dcbb..502de27df66072b22efc7ae11a606d1f5b30621f 100644 (file)
--- a/src/widgets/toolbox.cpp
+++ b/src/widgets/toolbox.cpp
" <separator />"
" <toolitem action='TextAlignAction' />"
" <separator />"
+ " <toolitem action='TextSuperscriptAction' />"
+ " <toolitem action='TextSubscriptAction' />"
+ " <separator />"
" <toolitem action='TextLineHeightAction' />"
" <toolitem action='TextLetterSpacingAction' />"
" <toolitem action='TextWordSpacingAction' />"
g_object_set_data( tbl, "freeze", GINT_TO_POINTER(FALSE) );
}
+// Handles both Superscripts and Subscripts
+static void sp_text_script_changed( InkToggleAction* act, GObject *tbl )
+{
+ // quit if run by the _changed callbacks
+ if (g_object_get_data(G_OBJECT(tbl), "freeze")) {
+ return;
+ }
+ g_object_set_data( tbl, "freeze", GINT_TO_POINTER(TRUE) );
+
+ // Called by Superscript or Subscript button?
+ const gchar* name = gtk_action_get_name( GTK_ACTION( act ) );
+ gint prop = (strcmp(name, "TextSuperscriptAction") == 0) ? 0 : 1;
+
+#ifdef DEBUG_TEXT
+ std::cout << "sp_text_script_changed: " << prop << std::endl;
+#endif
+
+ // Query baseline
+ SPStyle *query = sp_style_new (SP_ACTIVE_DOCUMENT);
+ int result_baseline = sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_BASELINES);
+
+ bool setSuper = false;
+ bool setSub = false;
+
+ if(result_baseline == QUERY_STYLE_NOTHING || result_baseline == QUERY_STYLE_MULTIPLE_DIFFERENT ) {
+ // If not set or mixed, turn on superscript or subscript
+ if( prop == 0 ) {
+ setSuper = true;
+ } else {
+ setSub = true;
+ }
+ } else {
+ // Superscript
+ gboolean superscriptSet = (query->baseline_shift.set &&
+ query->baseline_shift.type == SP_BASELINE_SHIFT_LITERAL &&
+ query->baseline_shift.literal == SP_CSS_BASELINE_SHIFT_SUPER );
+
+ // Subscript
+ gboolean subscriptSet = (query->baseline_shift.set &&
+ query->baseline_shift.type == SP_BASELINE_SHIFT_LITERAL &&
+ query->baseline_shift.literal == SP_CSS_BASELINE_SHIFT_SUB );
+
+ setSuper = !superscriptSet && prop == 0;
+ setSub = !subscriptSet && prop == 1;
+ }
+
+ // Set css properties
+ SPCSSAttr *css = sp_repr_css_attr_new ();
+ if( setSuper || setSub ) {
+ // Openoffice 2.3 and Adobe use 58%, Microsoft Word 2002 uses 65%.
+ sp_repr_css_set_property (css, "font-size", "58%");
+ } else {
+ sp_repr_css_set_property (css, "font-size", "");
+ }
+ if( setSuper ) {
+ sp_repr_css_set_property (css, "baseline-shift", "super");
+ } else if( setSub ) {
+ sp_repr_css_set_property (css, "baseline-shift", "sub");
+ } else {
+ sp_repr_css_set_property (css, "baseline-shift", "baseline");
+ }
+
+ // Apply css to selected objects.
+ SPDesktop *desktop = SP_ACTIVE_DESKTOP;
+ sp_desktop_set_style (desktop, css, true, true);
+
+ // Save for undo
+ sp_document_maybe_done (sp_desktop_document (SP_ACTIVE_DESKTOP), "ttb:script", SP_VERB_NONE,
+ _("Text: Change superscript or subscript"));
+
+ g_object_set_data( tbl, "freeze", GINT_TO_POINTER(FALSE) );
+}
+
static void sp_text_align_mode_changed( EgeSelectOneAction *act, GObject *tbl )
{
// quit if run by the _changed callbacks
@@ -7090,6 +7166,8 @@ static void sp_text_toolbox_selection_changed(Inkscape::Selection */*selection*/
int result_family = sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_FONTFAMILY);
int result_style = sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_FONTSTYLE);
int result_numbers = sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_FONTNUMBERS);
+ int result_baseline = sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_BASELINES);
+
// Used later:
sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_FONT_SPECIFICATION);
@@ -7161,8 +7239,32 @@ static void sp_text_toolbox_selection_changed(Inkscape::Selection */*selection*/
InkToggleAction* textItalicAction = INK_TOGGLE_ACTION( g_object_get_data( tbl, "TextItalicAction" ) );
gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(textItalicAction), italicSet );
- EgeSelectOneAction* textAlignAction = EGE_SELECT_ONE_ACTION( g_object_get_data( tbl, "TextAlignAction" ) );
+
+ // Superscript
+ gboolean superscriptSet =
+ ((result_baseline == QUERY_STYLE_SINGLE || result_baseline == QUERY_STYLE_MULTIPLE_SAME ) &&
+ query->baseline_shift.set &&
+ query->baseline_shift.type == SP_BASELINE_SHIFT_LITERAL &&
+ query->baseline_shift.literal == SP_CSS_BASELINE_SHIFT_SUPER );
+
+ InkToggleAction* textSuperscriptAction = INK_TOGGLE_ACTION( g_object_get_data( tbl, "TextSuperscriptAction" ) );
+ gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(textSuperscriptAction), superscriptSet );
+
+
+ // Subscript
+ gboolean subscriptSet =
+ ((result_baseline == QUERY_STYLE_SINGLE || result_baseline == QUERY_STYLE_MULTIPLE_SAME ) &&
+ query->baseline_shift.set &&
+ query->baseline_shift.type == SP_BASELINE_SHIFT_LITERAL &&
+ query->baseline_shift.literal == SP_CSS_BASELINE_SHIFT_SUB );
+
+ InkToggleAction* textSubscriptAction = INK_TOGGLE_ACTION( g_object_get_data( tbl, "TextSubscriptAction" ) );
+ gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(textSubscriptAction), subscriptSet );
+
+
// Alignment
+ EgeSelectOneAction* textAlignAction = EGE_SELECT_ONE_ACTION( g_object_get_data( tbl, "TextAlignAction" ) );
+
// Note: SVG 1.1 doesn't include text-align, SVG 1.2 Tiny doesn't include text-align="justify"
// text-align="justify" was a draft SVG 1.2 item (along with flowed text).
// Only flowed text can be left and right justified at the same time.
@@ -7432,6 +7534,32 @@ static void sp_text_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions
g_object_set_data( holder, "TextItalicAction", act );
}
+ /* Style - Superscript */
+ {
+ InkToggleAction* act = ink_toggle_action_new( "TextSuperscriptAction", // Name
+ _("Toggle Superscript"), // Label
+ _("Toggle superscript"), // Tooltip
+ GTK_STOCK_ITALIC, // Icon (inkId)
+ secondarySize ); // Icon size
+ gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
+ g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(sp_text_script_changed), holder );
+ gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act), prefs->getBool("/tools/text/super", false) );
+ g_object_set_data( holder, "TextSuperscriptAction", act );
+ }
+
+ /* Style - Subscript */
+ {
+ InkToggleAction* act = ink_toggle_action_new( "TextSubscriptAction", // Name
+ _("Toggle Subscript"), // Label
+ _("Toggle subscript"), // Tooltip
+ GTK_STOCK_ITALIC, // Icon (inkId)
+ secondarySize ); // Icon size
+ gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
+ g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(sp_text_script_changed), holder );
+ gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act), prefs->getBool("/tools/text/sub", false) );
+ g_object_set_data( holder, "TextSubscriptAction", act );
+ }
+
/* Alignment */
{
GtkListStore* model = gtk_list_store_new( 4, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_BOOLEAN );