summaryrefslogtreecommitdiffstats
path: root/src/libnrtype
diff options
context:
space:
mode:
authorMichael Soegtrop <MSoegtrop@yahoo.de>2017-06-05 13:56:11 +0000
committerMichael Soegtrop <MSoegtrop@yahoo.de>2017-06-05 13:56:11 +0000
commit7ee81350c73388881e60a59928d26764b7172c9b (patch)
treeb561a4dbbacd7eecbdbae3fa220a353375ccecf8 /src/libnrtype
parentupdated to trunk (diff)
parent[Bug #1695016] Xaml export misses some radialGradients. (diff)
downloadinkscape-7ee81350c73388881e60a59928d26764b7172c9b.tar.gz
inkscape-7ee81350c73388881e60a59928d26764b7172c9b.zip
merged with latest version of lpe-bool and trunk
(bzr r14862.2.3)
Diffstat (limited to 'src/libnrtype')
-rw-r--r--src/libnrtype/FontFactory.cpp137
-rw-r--r--src/libnrtype/Layout-TNG-Compute.cpp138
-rw-r--r--src/libnrtype/Layout-TNG-Output.cpp19
-rw-r--r--src/libnrtype/Layout-TNG-Scanline-Makers.cpp2
-rw-r--r--src/libnrtype/Layout-TNG.h15
-rw-r--r--src/libnrtype/Makefile_insert28
-rw-r--r--src/libnrtype/font-lister.cpp18
7 files changed, 197 insertions, 160 deletions
diff --git a/src/libnrtype/FontFactory.cpp b/src/libnrtype/FontFactory.cpp
index 65eb62dda..770616ae7 100644
--- a/src/libnrtype/FontFactory.cpp
+++ b/src/libnrtype/FontFactory.cpp
@@ -24,6 +24,9 @@
#include "util/unordered-containers.h"
#include <map>
+#include <harfbuzz/hb-ft.h>
+#include <harfbuzz/hb-ot.h>
+
typedef INK_UNORDERED_MAP<PangoFontDescription*, font_instance*, font_descr_hash, font_descr_equal> FaceMapType;
// need to avoid using the size field
@@ -99,7 +102,6 @@ font_factory::font_factory(void) :
fontSize(512),
loadedPtr(new FaceMapType())
{
- // std::cout << pango_version_string() << std::endl;
#ifdef USE_PANGO_WIN32
#else
pango_ft2_font_map_set_resolution(PANGO_FT2_FONT_MAP(fontServer),
@@ -293,6 +295,13 @@ void font_factory::GetUIFamilies(std::vector<PangoFontFamily *>& out)
const char* displayName = pango_font_family_get_name(families[currentFamily]);
if (displayName == 0 || *displayName == '\0') {
+ std::cerr << "font_factory::GetUIFamilies: Missing displayName! " << std::endl;
+ continue;
+ }
+ if (!g_utf8_validate(displayName, -1, 0)) {
+ // TODO: can can do anything about this or does it always indicate broken fonts that should not be used?
+ std::cerr << "font_factory::GetUIFamilies: Illegal characters in displayName. ";
+ std::cerr << "Ignoring font '" << displayName << "'" << std::endl;
continue;
}
sorted.push_back(std::make_pair(families[currentFamily], displayName));
@@ -311,6 +320,10 @@ GList* font_factory::GetUIStyles(PangoFontFamily * in)
// Gather the styles for this family
PangoFontFace** faces = NULL;
int numFaces = 0;
+ if (in == NULL) {
+ std::cerr << "font_factory::GetUIStyles(): PangoFontFamily is NULL" << std::endl;
+ return ret;
+ }
pango_font_family_list_faces(in, &faces, &numFaces);
for (int currentFace = 0; currentFace < numFaces; currentFace++) {
@@ -320,6 +333,7 @@ GList* font_factory::GetUIStyles(PangoFontFamily * in)
const gchar* displayName = pango_font_face_get_face_name(faces[currentFace]);
// std::cout << "Display Name: " << displayName << std::endl;
if (displayName == NULL || *displayName == '\0') {
+ std::cerr << "font_factory::GetUIStyles: Missing displayName! " << std::endl;
continue;
}
@@ -593,13 +607,15 @@ font_instance* font_factory::FaceFromFontSpecification(char const *fontSpecifica
return font;
}
-void dump_tag( guint32 *tag, Glib::ustring prefix = "" ) {
+void dump_tag( guint32 *tag, Glib::ustring prefix = "", bool lf=true ) {
std::cout << prefix
<< ((char)((*tag & 0xff000000)>>24))
<< ((char)((*tag & 0x00ff0000)>>16))
<< ((char)((*tag & 0x0000ff00)>>8))
- << ((char)((*tag & 0x000000ff)>>0))
- << std::endl;
+ << ((char)((*tag & 0x000000ff)>>0));
+ if( lf ) {
+ std::cout << std::endl;
+ }
}
Glib::ustring extract_tag( guint32 *tag ) {
@@ -677,74 +693,61 @@ font_instance *font_factory::Face(PangoFontDescription *descr, bool canFail)
}
// Extract which OpenType tables are in the font. We'll make a list of all tables
- // regardless of which script and langauge they are in. These functions are deprecated but
- // will eventually be replaced by newer functions (according to Behdad).
- PangoOTInfo* info = pango_ot_info_get( res->theFace );
-
- PangoOTTag* scripts = pango_ot_info_list_scripts( info, PANGO_OT_TABLE_GSUB );
- // std::cout << " scripts: " << std::endl;
- for( unsigned i = 0; scripts[i] != 0; ++i ) {
- // dump_tag( &scripts[i], " " );
-
- guint script_index = -1;
- if( pango_ot_info_find_script( info, PANGO_OT_TABLE_GSUB, scripts[i], &script_index )) {
-
- PangoOTTag* languages =
- pango_ot_info_list_languages( info, PANGO_OT_TABLE_GSUB, script_index, NULL);
- // if( languages[0] != 0 )
- // std::cout << " languages: " << std::endl;
-
- for( unsigned j = 0; languages[j] != 0; ++j ) {
- // dump_tag( &languages[j], " lang: ");
-
- guint language_index = -1;
- if( pango_ot_info_find_language(info, PANGO_OT_TABLE_GSUB, script_index, languages[j], &language_index, NULL)) {
-
- PangoOTTag* features =
- pango_ot_info_list_features( info, PANGO_OT_TABLE_GSUB, 0, i, j );
- if( features[0] != 0 )
- // std::cout << " features: " << std::endl;
-
- for( unsigned k = 0; features[k] != 0; ++k ) {
- // dump_tag( &features[k], " feature: ");
- ++(res->openTypeTables[ extract_tag(&features[k])]);
- }
- g_free( features );
- } else {
- // std::cout << " No languages defined" << std::endl;
- PangoOTTag* features =
- pango_ot_info_list_features( info, PANGO_OT_TABLE_GSUB, 0, i, PANGO_OT_DEFAULT_LANGUAGE );
- // if( features[0] != 0 )
- // std::cout << " default features: " << std::endl;
-
- for( unsigned k = 0; features[k] != 0; ++k ) {
- // dump_tag( &features[k], " feature: " );
- ++(res->openTypeTables[ extract_tag(&features[k])]);
- }
- g_free( features );
+ // regardless of which script and langauge they are in. This Harfbuzz code replaces
+ // an earlier Pango version as the Pango functions are deprecated.
+
+ // Empty map... bitmap fonts seem to be loaded multiple times.
+ res->openTypeTables.clear();
+
+ auto const hb_face = hb_ft_face_create(res->theFace, NULL);
+
+ // First time to get size of array
+ auto script_count = hb_ot_layout_table_get_script_tags(hb_face, HB_OT_TAG_GSUB, 0, NULL, NULL);
+ auto const scripts_hb = g_new(hb_tag_t, script_count + 1);
+
+ // Second time to fill array (this two step process was not necessary with Pango).
+ hb_ot_layout_table_get_script_tags(hb_face, HB_OT_TAG_GSUB, 0, &script_count, scripts_hb);
+
+ for(unsigned int i = 0; i < script_count; ++i) {
+ auto language_count = hb_ot_layout_script_get_language_tags(hb_face, HB_OT_TAG_GSUB, i, 0, NULL, NULL);
+
+ if(language_count > 0) {
+ auto const languages_hb = g_new(hb_tag_t, language_count + 1);
+ hb_ot_layout_script_get_language_tags(hb_face, HB_OT_TAG_GSUB, i, 0, &language_count, languages_hb);
+
+ for(unsigned int j = 0; j < language_count; ++j) {
+ auto feature_count = hb_ot_layout_language_get_feature_tags(hb_face, HB_OT_TAG_GSUB, i, j, 0, NULL, NULL);
+ auto const features_hb = g_new(hb_tag_t, feature_count + 1);
+ hb_ot_layout_language_get_feature_tags(hb_face, HB_OT_TAG_GSUB, i, j, 0, &feature_count, features_hb);
+
+ for(unsigned int k = 0; k < feature_count; ++k) {
+ ++(res->openTypeTables[ extract_tag(&features_hb[k])]);
}
+
+ g_free(features_hb);
}
- g_free( languages );
- } else {
- // std::cout << " No scripts defined! " << std::endl;
+
+ g_free(languages_hb);
+ }
+ else {
+ // Even if no languages are present there is still the default.
+ auto feature_count = hb_ot_layout_language_get_feature_tags(hb_face, HB_OT_TAG_GSUB, i,
+ HB_OT_LAYOUT_DEFAULT_LANGUAGE_INDEX,
+ 0, NULL, NULL);
+ auto const features_hb = g_new(hb_tag_t, feature_count + 1);
+ hb_ot_layout_language_get_feature_tags(hb_face, HB_OT_TAG_GSUB, i,
+ HB_OT_LAYOUT_DEFAULT_LANGUAGE_INDEX,
+ 0, &feature_count, features_hb);
+
+ for(unsigned int k = 0; k < feature_count; ++k) {
+ ++(res->openTypeTables[ extract_tag(&features_hb[k])]);
+ }
+
+ g_free(features_hb);
}
}
- g_free( scripts );
-
- PangoOTTag* features =
- pango_ot_info_list_features( info, PANGO_OT_TABLE_GSUB, 0, 0, PANGO_OT_DEFAULT_LANGUAGE );
- // if( features[0] != 0 )
- // std::cout << " DFTL DFTL features: " << std::endl;
- for( unsigned i = 0; features[i] != 0; ++i ) {
- // dump_tag( &features[i], " feature: " );
- ++(res->openTypeTables[ extract_tag(&features[i])]);
- }
- // std::map<Glib::ustring,int>::iterator it;
- // for( it = res->openTypeTables.begin(); it != res->openTypeTables.end(); ++it) {
- // std::cout << "Table: " << it->first << " Occurances: " << it->second << std::endl;
- // }
- g_free( features );
+ g_free(scripts_hb);
} else {
// already here
res = loadedFaces[descr];
diff --git a/src/libnrtype/Layout-TNG-Compute.cpp b/src/libnrtype/Layout-TNG-Compute.cpp
index 337d2a656..8e173a7c7 100644
--- a/src/libnrtype/Layout-TNG-Compute.cpp
+++ b/src/libnrtype/Layout-TNG-Compute.cpp
@@ -210,6 +210,7 @@ class Layout::Calculator
*/
static void dumpPangoItemsOut(ParagraphInfo *para){
std::cout << "Pango items: " << para->pango_items.size() << std::endl;
+ font_factory * factory = font_factory::Default();
for(unsigned pidx = 0 ; pidx < para->pango_items.size(); pidx++){
std::cout
<< "idx: " << pidx
@@ -217,6 +218,8 @@ static void dumpPangoItemsOut(ParagraphInfo *para){
<< para->pango_items[pidx].item->offset
<< " length: "
<< para->pango_items[pidx].item->length
+ << " font: "
+ << factory->ConstructFontSpecification( para->pango_items[pidx].font )
<< std::endl;
}
}
@@ -243,8 +246,11 @@ static void dumpUnbrokenSpans(ParagraphInfo *para){
bool _goToNextWrapShape();
- bool _findChunksForLine(ParagraphInfo const &para, UnbrokenSpanPosition *start_span_pos,
- std::vector<ChunkInfo> *chunk_info, FontMetrics *line_box_height);
+ bool _findChunksForLine(ParagraphInfo const &para,
+ UnbrokenSpanPosition *start_span_pos,
+ std::vector<ChunkInfo> *chunk_info,
+ FontMetrics *line_box_height,
+ FontMetrics const *strut_height);
static inline PangoLogAttr const &_charAttributes(ParagraphInfo const &para,
UnbrokenSpanPosition const &span_pos)
@@ -1138,31 +1144,17 @@ void Layout::Calculator::_buildPangoItemizationForPara(ParagraphInfo *para) con
*/
double Layout::Calculator::_computeFontLineHeight( SPStyle const *style )
{
- // yet another borked SPStyle member that we're going to have to fix ourselves
- // We shouldn't need to climb the element tree...
- for ( ; ; ) {
- if (style->line_height.set && !style->line_height.inherit) {
- if (style->line_height.normal)
- break;
- switch (style->line_height.unit) {
- case SP_CSS_UNIT_NONE:
- return style->line_height.computed;
- case SP_CSS_UNIT_EX:
- return style->line_height.value * 0.5;
- // 0.5 is an approximation of the x-height. Fixme.
- case SP_CSS_UNIT_EM:
- case SP_CSS_UNIT_PERCENT:
- return style->line_height.value;
- default: // absolute values
- return style->line_height.computed / style->font_size.computed;
- }
- break;
- }
- if (style->object == NULL || style->object->parent == NULL) break;
- style = style->object->parent->style;
- if (style == NULL) break;
+ // This is a bit backwards... we should be returning the absolute height
+ // but as the code expects line_height_multiplier we return that.
+ if (style->line_height.normal) {
+ return (LINE_HEIGHT_NORMAL);
+ } else if (style->line_height.unit == SP_CSS_UNIT_NONE) {
+ // Special case per CSS, computed value is multiplier
+ return style->line_height.computed;
+ } else {
+ // Normal case, computed value is absolute height. Turn it into multiplier.
+ return style->line_height.computed / style->font_size.computed;
}
- return (LINE_HEIGHT_NORMAL);
}
bool compareGlyphWidth(const PangoGlyphInfo &a, const PangoGlyphInfo &b)
@@ -1193,10 +1185,34 @@ unsigned Layout::Calculator::_buildSpansForPara(ParagraphInfo *para) const
for(input_index = para->first_input_index ; input_index < _flow._input_stream.size() ; input_index++) {
if (_flow._input_stream[input_index]->Type() == CONTROL_CODE) {
Layout::InputStreamControlCode const *control_code = static_cast<Layout::InputStreamControlCode const *>(_flow._input_stream[input_index]);
+
if ( control_code->code == SHAPE_BREAK
- || control_code->code == PARAGRAPH_BREAK)
+ || control_code->code == PARAGRAPH_BREAK) {
+
+ // Add span to be used to calculate line spacing of blank lines.
+ UnbrokenSpan new_span;
+ new_span.pango_item_index = -1;
+ new_span.input_index = input_index;
+
+ // No pango object, so find font and line height ourselves.
+ SPObject * object = static_cast<SPObject *>(control_code->source_cookie);
+ if (object) {
+ SPStyle * style = object->style;
+ if (style) {
+ new_span.font_size = style->font_size.computed * _flow.getTextLengthMultiplierDue();
+ font_factory * factory = font_factory::Default();
+ font_instance * font = factory->FaceFromStyle( style );
+ new_span.line_height_multiplier = _computeFontLineHeight( object->style );
+ new_span.line_height.set( font );
+ new_span.line_height *= new_span.font_size;
+ }
+ }
+ new_span.text_bytes = 0;
+ new_span.char_index_in_para = char_index_in_para;
+ para->unbroken_spans.push_back(new_span);
+ TRACE(("add empty span for break %lu\n", para->unbroken_spans.size() - 1));
break; // stop at the end of the paragraph
- else if (control_code->code == ARBITRARY_GAP) {
+ } else if (control_code->code == ARBITRARY_GAP) {
UnbrokenSpan new_span;
new_span.pango_item_index = -1;
new_span.input_index = input_index;
@@ -1449,42 +1465,39 @@ bool Layout::Calculator::_goToNextWrapShape()
* line to #_flow. Returns with \a start_span_pos set to the end of the
* text that was fitted, \a chunk_info completely filled out and
* \a line_box_height set with the largest ascent and the largest
- * descent (individually per CSS) on the line. The return
+ * descent (individually per CSS) on the line. The line_box_height
+ * can never be smaller than the line_box_strut (which is determined
+ * by the block level value of line_height). The return
* value is false only if we've run out of shapes to wrap inside (and
* hence couldn't create any chunks).
*/
bool Layout::Calculator::_findChunksForLine(ParagraphInfo const &para,
UnbrokenSpanPosition *start_span_pos,
std::vector<ChunkInfo> *chunk_info,
- FontMetrics *line_box_height)
+ FontMetrics *line_box_height,
+ FontMetrics const *strut_height)
{
TRACE((" begin _findChunksForLine: chunks: %lu, em size: %f\n", chunk_info->size(), line_box_height->emSize() ));
- // CSS 2.1 dictates that the minimum line height (i.e. the strut height) is found from the block element. This,
- // however, is not what the browsers seem to be doing. Instead, find the height from the first text source.
- InputStreamTextSource const *text_source = static_cast<InputStreamTextSource const *>(_flow._input_stream.front());
- font_instance *font = text_source->styleGetFontInstance();
- if (font) {
- double multiplier = _computeFontLineHeight(text_source->style);
- line_box_height->set( font );
- *line_box_height *= text_source->style->font_size.computed;
- font->Unref();
- line_box_height->computeEffective( multiplier );
- } else {
- std::cerr << "Layout::Calculator::_findChunksForLine: Font not found." << std::endl;
- }
+ // CSS 2.1 dictates that the minimum line height (i.e. the strut height)
+ // is found from the block element.
+ *line_box_height = *strut_height;
TRACE((" initial line_box_height (em size): %f\n", line_box_height->emSize() ));
- // Save strut height for use when recalculating line height after backing out chunks that don't fit.
- FontMetrics strut_height = *line_box_height;
-
UnbrokenSpanPosition span_pos;
for( ; ; ) {
+
+ // Get regions where one can place one line of text (can be more than one, if filling a
+ // donut for example).
std::vector<ScanlineMaker::ScanRun> scan_runs;
scan_runs = _scanline_maker->makeScanline(*line_box_height); // Only one line with "InfiniteScanlineMaker
+
+ // If scan_runs is empty, we must have reached the bottom of a shape. Go to next shape.
while (scan_runs.empty()) {
// Only used by ShapeScanlineMaker
if (!_goToNextWrapShape()) return false; // no more shapes to wrap in to
+
+ *line_box_height = *strut_height;
scan_runs = _scanline_maker->makeScanline(*line_box_height);
}
@@ -1495,13 +1508,21 @@ bool Layout::Calculator::_findChunksForLine(ParagraphInfo const &para,
unsigned scan_run_index;
span_pos = *start_span_pos;
for (scan_run_index = 0 ; scan_run_index < scan_runs.size() ; scan_run_index++) {
- if (!_buildChunksInScanRun(para, span_pos, scan_runs[scan_run_index], chunk_info, line_box_height, &strut_height))
+
+ // Returns false if some text in line requires a taller line_box_height.
+ // (We try again with a larger line_box_height.)
+ if (!_buildChunksInScanRun(para, span_pos, scan_runs[scan_run_index], chunk_info, line_box_height, strut_height)) {
break;
+ }
+
if (!chunk_info->empty() && !chunk_info->back().broken_spans.empty())
span_pos = chunk_info->back().broken_spans.back().end;
}
+
if (scan_run_index == scan_runs.size()) break; // ie when buildChunksInScanRun() succeeded
- }
+
+ } // End for loop
+
*start_span_pos = span_pos;
TRACE((" final line_box_height: %f\n", line_box_height->emSize() ));
TRACE((" end _findChunksForLine: chunks: %lu\n", chunk_info->size()));
@@ -1568,12 +1589,15 @@ bool Layout::Calculator::_buildChunksInScanRun(ParagraphInfo const &para,
// see if this span is too tall to fit on the current line
FontMetrics new_span_height = new_span.start.iter_span->line_height;
new_span_height.computeEffective( new_span.start.iter_span->line_height_multiplier );
+
/* floating point 80-bit/64-bit rounding problems require epsilon. See
discussion http://inkscape.gristle.org/2005-03-16.txt around 22:00 */
if ( new_span_height.ascent > line_height->ascent + std::numeric_limits<float>::epsilon() ||
new_span_height.descent > line_height->descent + std::numeric_limits<float>::epsilon() ) {
// Take larger of each of the two ascents and two descents per CSS
line_height->max(new_span_height);
+
+ // Currently always true for flowed text and false for Inkscape multiline text.
if (!_scanline_maker->canExtendCurrentScanline(*line_height)) {
return false;
}
@@ -1639,8 +1663,8 @@ bool Layout::Calculator::_buildChunksInScanRun(ParagraphInfo const &para,
*line_height = *strut_height;
for (std::vector<ChunkInfo>::const_iterator it_chunk = chunk_info->begin() ; it_chunk != chunk_info->end() ; it_chunk++) {
for (std::vector<BrokenSpan>::const_iterator it_span = it_chunk->broken_spans.begin() ; it_span != it_chunk->broken_spans.end() ; it_span++) {
- TRACE((" brokenspan line_height: %f\n", it_span->start.iter_span->line_height.emSize() ));
FontMetrics span_height = it_span->start.iter_span->line_height;
+ TRACE((" brokenspan line_height: %f\n", span_height.emSize() ));
span_height.computeEffective( it_span->start.iter_span->line_height_multiplier );
line_height->max( span_height );
}
@@ -1705,11 +1729,13 @@ bool Layout::Calculator::calculate()
pango_context_set_base_gravity(_pango_context, PANGO_GRAVITY_AUTO);
}
+ // Minimum line box height determined by block container.
+ FontMetrics strut_height = _flow.strut;
_y_offset = 0.0;
_createFirstScanlineMaker();
ParagraphInfo para;
- FontMetrics line_box_height; // needs to be maintained across paragraphs to be able to deal with blank paras
+ FontMetrics line_box_height; // Current value of line box height for line.
for(para.first_input_index = 0 ; para.first_input_index < _flow._input_stream.size() ; ) {
// jump to the next wrap shape if this is a SHAPE_BREAK control code
if (_flow._input_stream[para.first_input_index]->Type() == CONTROL_CODE) {
@@ -1746,12 +1772,20 @@ bool Layout::Calculator::calculate()
span_pos.char_byte = 0;
span_pos.char_index = 0;
+ bool keep_going = true;
do { // for each line in the paragraph
TRACE(("begin line\n"));
+
std::vector<ChunkInfo> line_chunk_info;
- if (!_findChunksForLine(para, &span_pos, &line_chunk_info, &line_box_height))
+ if (!_findChunksForLine(para, &span_pos, &line_chunk_info, &line_box_height, &strut_height )) {
+ keep_going = false;
break; // out of shapes to wrap in to
+ }
+ if (line_box_height.emSize() < 0.001 && line_chunk_info.empty()) {
+ keep_going = false;
+ break; // No room for text and not useful to try again at same place.
+ }
_outputLine(para, line_box_height, line_chunk_info);
_scanline_maker->setLineHeight( line_box_height );
_scanline_maker->completeLine(); // Increments y by line height
@@ -1759,7 +1793,7 @@ bool Layout::Calculator::calculate()
} while (span_pos.iter_span != para.unbroken_spans.end());
TRACE(("para %lu end\n\n", _flow._paragraphs.size() - 1));
- if (_scanline_maker != NULL) {
+ if (keep_going) {
bool is_empty_para = _flow._characters.empty() || _flow._characters.back().line(&_flow).in_paragraph != _flow._paragraphs.size() - 1;
if ((is_empty_para && para_end_input_index + 1 >= _flow._input_stream.size())
|| para_end_input_index + 1 < _flow._input_stream.size()) {
diff --git a/src/libnrtype/Layout-TNG-Output.cpp b/src/libnrtype/Layout-TNG-Output.cpp
index 526319f35..a1a19f2b3 100644
--- a/src/libnrtype/Layout-TNG-Output.cpp
+++ b/src/libnrtype/Layout-TNG-Output.cpp
@@ -742,8 +742,6 @@ void Layout::fitToPathAlign(SVGLength const &startOffset, Path const &path)
if (endpoint != startpoint) {
tangent = endpoint - startpoint;
tangent.normalize();
- } else {
- tangent = Geom::Point (0,0);
}
}
g_free(end_otp);
@@ -869,6 +867,23 @@ double Layout::getActualLength() const
}//namespace Text
}//namespace Inkscape
+std::ostream &operator<<(std::ostream &out, const Inkscape::Text::Layout::FontMetrics &f) {
+ out << " emSize: " << f.emSize()
+ << " ascent: " << f.ascent
+ << " descent: " << f.descent
+ << " xheight: " << f.xheight;
+ return out;
+}
+
+std::ostream &operator<<(std::ostream &out, const Inkscape::Text::Layout::FontMetrics *f) {
+ out << " emSize: " << f->emSize()
+ << " ascent: " << f->ascent
+ << " descent: " << f->descent
+ << " xheight: " << f->xheight;
+ return out;
+}
+
+
/*
Local Variables:
diff --git a/src/libnrtype/Layout-TNG-Scanline-Makers.cpp b/src/libnrtype/Layout-TNG-Scanline-Makers.cpp
index 0d6112d19..a57aaa3e4 100644
--- a/src/libnrtype/Layout-TNG-Scanline-Makers.cpp
+++ b/src/libnrtype/Layout-TNG-Scanline-Makers.cpp
@@ -124,7 +124,7 @@ std::vector<Layout::ScanlineMaker::ScanRun> Layout::ShapeScanlineMaker::makeScan
FloatLigne line_rasterization;
FloatLigne line_decent_length_runs;
float line_text_height = (float)(line_height.emSize());
- if (line_text_height == 0.0)
+ if (line_text_height < 0.001)
line_text_height = 0.001; // Scan() doesn't work for zero height so this will have to do
_current_line_height = (float)line_height.emSize();
diff --git a/src/libnrtype/Layout-TNG.h b/src/libnrtype/Layout-TNG.h
index 97a05bde8..c39315106 100644
--- a/src/libnrtype/Layout-TNG.h
+++ b/src/libnrtype/Layout-TNG.h
@@ -194,7 +194,7 @@ public:
/** For expressing paragraph alignment. These values are rotated in the
case of vertical text, but are not dependent on whether the paragraph is
rtl or ltr, thus LEFT is always either left or top. */
- enum Alignment {LEFT, CENTER, RIGHT, FULL};
+ enum Alignment {LEFT, CENTER, RIGHT, FULL, NONE};
/** The CSS spec allows line-height:normal to be whatever the user agent
thinks will look good. This is our value, as a multiple of font-size. */
@@ -629,7 +629,7 @@ public:
void reset() {
ascent = 0.8;
- descent = -0.2;
+ descent = 0.2;
xheight = 0.5;
ascent_max = 0.8;
descent_max = 0.2;
@@ -664,13 +664,16 @@ public:
// private:
double ascent; // Typographic ascent.
- double descent; // Typographic descent.
+ double descent; // Typographic descent. (Normally positive).
double xheight; // Height of 'x' measured from alphabetic baseline.
double ascent_max; // Maximum ascent of all glyphs in font.
double descent_max; // Maximum descent of all glyphs in font.
}; // End FontMetrics
+ /** The strut is the minimum value used in calculating line height. */
+ FontMetrics strut;
+
/// see _enum_converter()
struct EnumConversionItem {
int input, output;
@@ -1141,7 +1144,7 @@ inline unsigned Layout::paragraphIndex(iterator const &it) const
{return it._char_index == _characters.size() ? _paragraphs.size() - 1 : _characters[it._char_index].line(this).in_paragraph;}
inline Layout::Alignment Layout::paragraphAlignment(iterator const &it) const
- {return _paragraphs[paragraphIndex(it)].alignment;}
+ {return (_paragraphs.size() == 0) ? NONE : _paragraphs[paragraphIndex(it)].alignment;}
inline bool Layout::iterator::nextGlyph()
{
@@ -1186,6 +1189,10 @@ inline bool Layout::iterator::prevCharacter()
}//namespace Text
}//namespace Inkscape
+std::ostream &operator<<(std::ostream &out, const Inkscape::Text::Layout::FontMetrics &f);
+std::ostream &operator<<(std::ostream &out, const Inkscape::Text::Layout::FontMetrics *f);
+
+
#endif
diff --git a/src/libnrtype/Makefile_insert b/src/libnrtype/Makefile_insert
deleted file mode 100644
index ab9465daa..000000000
--- a/src/libnrtype/Makefile_insert
+++ /dev/null
@@ -1,28 +0,0 @@
-## Makefile.am fragment sourced by src/Makefile.am.
-
-ink_common_sources += \
- libnrtype/boundary-type.h \
- libnrtype/font-glyph.h \
- libnrtype/font-instance.h \
- libnrtype/font-style.h \
- libnrtype/nr-type-primitives.cpp \
- libnrtype/nr-type-primitives.h \
- libnrtype/FontFactory.cpp \
- libnrtype/FontFactory.h \
- libnrtype/FontInstance.cpp \
- libnrtype/font-lister.h \
- libnrtype/font-lister.cpp \
- libnrtype/one-box.h \
- libnrtype/one-glyph.h \
- libnrtype/one-para.h \
- libnrtype/text-boundary.h \
- libnrtype/TextWrapper.cpp \
- libnrtype/TextWrapper.h \
- libnrtype/Layout-TNG-Compute.cpp \
- libnrtype/Layout-TNG-Input.cpp \
- libnrtype/Layout-TNG-OutIter.cpp \
- libnrtype/Layout-TNG-Output.cpp \
- libnrtype/Layout-TNG-Scanline-Maker.h \
- libnrtype/Layout-TNG-Scanline-Makers.cpp \
- libnrtype/Layout-TNG.cpp \
- libnrtype/Layout-TNG.h
diff --git a/src/libnrtype/font-lister.cpp b/src/libnrtype/font-lister.cpp
index 568a7c8cc..48fcf2a22 100644
--- a/src/libnrtype/font-lister.cpp
+++ b/src/libnrtype/font-lister.cpp
@@ -135,6 +135,8 @@ void FontLister::ensureRowStyles(GtkTreeModel* model, GtkTreeIter const* iterato
if (!row[FontList.styles]) {
if (row[FontList.pango_family]) {
row[FontList.styles] = font_factory::Default()->GetUIStyles(row[FontList.pango_family]);
+ } else {
+ row[FontList.styles] = default_styles;
}
}
}
@@ -177,6 +179,7 @@ void FontLister::insert_font_family(Glib::ustring new_family)
(*treeModelIter)[FontList.family] = new_family;
(*treeModelIter)[FontList.styles] = styles;
(*treeModelIter)[FontList.onSystem] = false;
+ (*treeModelIter)[FontList.pango_family] = NULL;
}
void FontLister::update_font_list(SPDocument *document)
@@ -256,7 +259,8 @@ void FontLister::update_font_list(SPDocument *document)
Gtk::TreeModel::iterator treeModelIter = font_list_store->prepend();
(*treeModelIter)[FontList.family] = reinterpret_cast<const char *>(g_strdup((*i).c_str()));
(*treeModelIter)[FontList.styles] = styles;
- (*treeModelIter)[FontList.onSystem] = false;
+ (*treeModelIter)[FontList.onSystem] = false; // false if document font
+ (*treeModelIter)[FontList.pango_family] = NULL; // CHECK ME (set to pango_family if on system?)
}
@@ -298,8 +302,8 @@ void FontLister::update_font_list_recursive(SPObject *r, std::list<Glib::ustring
l->push_back(Glib::ustring(font_family));
}
- for (SPObject *child = r->firstChild(); child; child = child->getNext()) {
- update_font_list_recursive(child, l);
+ for (auto& child: r->children) {
+ update_font_list_recursive(&child, l);
}
}
@@ -993,7 +997,7 @@ Glib::ustring FontLister::get_best_style_match(Glib::ustring family, Glib::ustri
}
catch (...)
{
- //std::cout << " ERROR: can't find family: " << family << std::endl;
+ std::cerr << "FontLister::get_best_style_match(): can't find family: " << family << std::endl;
return (target_style);
}
@@ -1002,10 +1006,12 @@ Glib::ustring FontLister::get_best_style_match(Glib::ustring family, Glib::ustri
//font_description_dump( target );
- if (!row[FontList.styles]) {
+ GList *styles = default_styles;
+ if (row[FontList.onSystem] && !row[FontList.styles]) {
row[FontList.styles] = font_factory::Default()->GetUIStyles(row[FontList.pango_family]);
+ styles = row[FontList.styles];
}
- GList *styles = row[FontList.styles];
+
for (GList *l = styles; l; l = l->next) {
Glib::ustring fontspec = family + ", " + ((StyleNames *)l->data)->CssName;
PangoFontDescription *candidate = pango_font_description_from_string(fontspec.c_str());