View Issue Details

IDProjectCategoryView StatusLast Update
0009611ScribusFontspublic2018-05-15 06:49
Reporterjiero Assigned Topierremarchand  
PrioritynormalSeveritytextReproducibilityalways
Status assignedResolutionopen 
PlatformAll OSAllOS VersionAll
Product Version1.4.0svn 
Target Version1.5.4Fixed in Version 
Summary0009611: Font substitute option: mainly needed by Asian/Other Language user as if glyphs missing or ugly
DescriptionFont substitute for text with two or more Languages combination, for example,Chinese and English, then the text imported with format probably using font that do not contain Chinese glyphs, which require a substitute font setting.

___________________________________________


Christoph:

sounds like a stupid thing: if [Unicode xyz], use font [abc]
Steps To ReproduceImport a paragraph with both Chinese and English using Chinese font, the English text looks ugly; if Change the font to a better-looking Latin font then all Chinese characters in block(no glyphs)
TagsCJK, scribusctl
PatchNo

Activities

ale

2010-12-23 07:14

manager   ~0025182

we should check with professional chinese graphic designers / print specialists and see if and how we should implement this.

jiero

2010-12-26 09:55

reporter   ~0025206

?. ?? Categorized
????????4????????????????????
All punctuation classified into 4- they all locate at left bottom corner; full???half??????center??
??1. Full ?? - ??????full??
       ??????????????????——2???/?????
??Force the punctuation have same widith to a Chinese Character
??2. Half ?? - ??????half??
       ??????????????????——1???/?????
??Force the punctuation have half of the widith to a Chinese Character

??3???
?? Except period ???question mark ???exclamation ??? occupy full?all else occupy half
???????????????????????
?? when multiple Chinese Punctuation join together, those in front forced half
???????????????????
????????????? ——? the "?"use half
?????? ——Question Mark use half
???????? ——First 3 exclamation use half, the last one use full
???
??4?Center
??All punctuations in center of full Chinese character- like traditional Chinese

?. Line-start and Line-end ????????????
??
       1. Avoid any punctutations at line-start

??2. when line-end not enough for a punctuation(even half)?or the punctuation is one avoiding line-start/line-end
??? WPS will force the line-end punctuation to next line and use justify space between characters in current line.
Wps?????????????????????????????????????

??? Microsoft Office Word: first try to shorten same line punctations.
????????????????try to let a space for it ????????????????????
??? Founder use similar method with wps, ???????????????????????????????????????
??Example:
??? Normally, line-end have half a Chinese character widith, with a full-stop.
???wps push the last character and full-stop to next line, then lack of 1.5 character space. Justify.
??? Word or Founder will directly place the full-stop there.
??? As the normal order, when line-end left no space at all.
??? Wps????????
    WPS keep pushing down 1 character and the punctutation to next line
??? Word????????????????????????????????? M$ word keep compress space of the other punctutations in this line( result in less space than "full")

??? ???wps?????????????????????????????????????????
    Founder have similar behaviour to WPS, pushing to next line.
    
??? ?????????????????????????
In normal order, the line-last have
??? Wps????????????????
??? Word?????????????????????
????????????????????
??? ???wps??????????????
    3. Line-start punctiuation compression
    3????????

jiero

2010-12-27 09:56

reporter   ~0025212

General Rules In Current Chinese Desktop Publishing Typography


Characters
Chinese Character width 2 Latin characters, and they are individually consider as words rather than characters.
Mixture of Chinese and other
As Chinese characters are independent to others, so normally there is a gap between La/Num/Symbol and Chinese Character; its often about 1/4 Chinese character width.
Punctuation out of concerns here, neither FULL nor HALF have gap between them and La/Num/Symbol.


Punctuations
Chinese punctuation use same width as Characters called in FULL, if width equal to non-Chinese character is called in HALF.

Chinese punctuation are not appearing in very beginning of a paragraph and mostly forbidden to starting a line.
Compressing Space for Punctuations
When a line come to the end with no space for a punctuation in FULL, then we prefer to make the punctuation in HALF or even no space for HALF then move the last word to next line.
When multiple punctuations are close one another, then only the last one in FULL, else in HALF.

Kunda

2016-04-11 19:33

manager   ~0040087

@jiero, can you come test the new experimental CJK text integration in to scribus? https://github.com/HOST-Oman/scribus/issues/143
Thanks

Fahad

2018-05-15 06:49

developer   ~0045244

Here is a patch that add a basic Font substitution. Here is how does look like:
https://github.com/HOST-Oman/scribus/issues/110#issuecomment-260580402

basicFontsubstitute.patch (12,520 bytes)
From 1117015d0796db213b880157a4fe0b758967ce58 Mon Sep 17 00:00:00 2001
From: Fahad <fahad.alsaidi@gmail.com>
Date: Tue, 15 May 2018 10:34:36 +0400
Subject: add basic font fallback support

This is a basic font fallback support feature. Right now, it takes one
font but in future it may takes more than one font. Fallback font is not
saved in scribus format, thus once you set fallback font, missing
faces's font style will change.

diff --git a/scribus/text/itextsource.h b/scribus/text/itextsource.h
index 41c88d4..f7cdd0e 100644
--- a/scribus/text/itextsource.h
+++ b/scribus/text/itextsource.h
@@ -51,6 +51,7 @@ public:
 	
 	virtual const ITextSource* parent() const { return nullptr; }
 	virtual int parentPos() const { return 0; }
+    virtual void setMissingFaces(QList<GlyphCluster> &missingFacesList) = 0;
 	
 	const ITextSource* original() const
     {
diff --git a/scribus/text/storytext.cpp b/scribus/text/storytext.cpp
index 8276c93..481ddce 100644
--- a/scribus/text/storytext.cpp
+++ b/scribus/text/storytext.cpp
@@ -2002,6 +2002,35 @@ void StoryText::invalidate(int firstItem, int endItem)
 		emit changed(firstItem, endItem);
 }
 
+void StoryText::setMissingFaces(QList<GlyphCluster> &missingFacesList)
+{
+    m_missingFacesList = missingFacesList;
+}
+
+QList<GlyphCluster> StoryText::missingFaces() const
+{
+    return m_missingFacesList;
+}
+
+void StoryText::setFallBackFont(const QString font)
+{
+    m_fallBackFont = font;
+}
+
+QString StoryText::fallBackFont() const
+{
+    return m_fallBackFont;
+}
+
+void StoryText::setFallBackFontSize(const double size)
+{
+    m_fallBackFontSize = size;
+}
+
+double StoryText::fallBackFontSize() const
+{
+    return m_fallBackFontSize;
+}
 
 // physical view
 
diff --git a/scribus/text/storytext.h b/scribus/text/storytext.h
index 0693f51..d85aa70 100644
--- a/scribus/text/storytext.h
+++ b/scribus/text/storytext.h
@@ -36,6 +36,7 @@ pageitem.cpp  -  description
 #include "marks.h"
 #include "text/frect.h"
 #include "text/specialchars.h"
+#include "text/glyphcluster.h"
 #include "sctextstruct.h"
 #include "style.h"
 #include "styles/charstyle.h"
@@ -268,6 +269,16 @@ class SCRIBUS_API StoryText : public QObject, public SaxIO, public ITextSource
  	/// call this if the shape of the paragraph changes (redos layout)
  	void invalidateLayout();
 
+    // return all missing faces ( glyhp.id == 0)
+    QList<GlyphCluster> missingFaces() const;
+    void setMissingFaces(QList<GlyphCluster> &missingFacesList);
+    // return the fallback font for this story text
+    QString fallBackFont() const;
+    void setFallBackFont(const QString font);
+    // return the size of the size of the fallback font
+    void setFallBackFontSize(const double size);
+    double fallBackFontSize() const;
+
 public slots:
 	/// call this if some logical style changes (redos shaping and layout)
  	void invalidateAll();
@@ -309,6 +320,9 @@ private:
 // 	uint layouterVersion;
  	/// is true after layout() has been exercised
 // 	bool layouterValid;
+    QList<GlyphCluster> m_missingFacesList;
+    QString m_fallBackFont;
+    double m_fallBackFontSize = 0;
  };
 
 
diff --git a/scribus/text/textshaper.cpp b/scribus/text/textshaper.cpp
index 53983a5..4be6b46 100644
--- a/scribus/text/textshaper.cpp
+++ b/scribus/text/textshaper.cpp
@@ -472,6 +472,10 @@ ShapedText TextShaper::shape(int fromPos, int toPos)
 			{
 				GlyphLayout gl;
 				gl.glyph = glyphs[i].codepoint;
+
+                if (gl.glyph == 0)
+                    m_missingFacesList.append(run);
+
 				if (gl.glyph == 0 ||
 				    (ch == SpecialChars::LINEBREAK || ch == SpecialChars::PARSEP ||
 				     ch == SpecialChars::FRAMEBREAK || ch == SpecialChars::COLBREAK))
@@ -640,6 +644,7 @@ ShapedText TextShaper::shape(int fromPos, int toPos)
 
 	m_textMap.clear();
 	m_text = "";
+    m_story.setMissingFaces(m_missingFacesList);
 	result.needsContext(m_contextNeeded);
 	return result;
 }
diff --git a/scribus/text/textshaper.h b/scribus/text/textshaper.h
index fa97dff..65289fe 100644
--- a/scribus/text/textshaper.h
+++ b/scribus/text/textshaper.h
@@ -68,6 +68,7 @@ private:
 	bool m_singlePar;
 	QString m_text;
 	QMap<int, int> m_textMap;
+    QList<GlyphCluster> m_missingFacesList;
 };
 
 #endif // TEXTSHAPER_H
diff --git a/scribus/ui/propertywidget_advanced.cpp b/scribus/ui/propertywidget_advanced.cpp
index 0bb755d..17239eb 100644
--- a/scribus/ui/propertywidget_advanced.cpp
+++ b/scribus/ui/propertywidget_advanced.cpp
@@ -10,10 +10,12 @@ for which a new license (GPL+exception) is in place.
 #include "appmodes.h"
 #include "iconmanager.h"
 #include "pageitem_table.h"
+#include "prefsmanager.h"
 #include "scribus.h"
 #include "scribusdoc.h"
 #include "selection.h"
 #include "units.h"
+#include "util.h"
 
 PropertyWidget_Advanced::PropertyWidget_Advanced(QWidget* parent) : QFrame(parent)
 {
@@ -45,6 +47,11 @@ PropertyWidget_Advanced::PropertyWidget_Advanced(QWidget* parent) : QFrame(paren
 	minGlyphExtensionLabel->setBuddy(minGlyphExtSpinBox);
 	maxGlyphExtensionLabel->setBuddy(maxGlyphExtSpinBox);
 
+    fallBackFont->setMaximumSize(190, 30);
+    PrefsManager* prefsManager = PrefsManager::instance();
+    fontFallBackSize->setSuffix( unitGetSuffixFromIndex(SC_POINTS) );
+    fontFallBackSize->setValue(prefsManager->appPrefs.itemToolPrefs.textSize / 10.0);
+
 	languageChange();
 }
 
@@ -128,6 +135,8 @@ void PropertyWidget_Advanced::connectSignals()
 	connect(normWordTrackingSpinBox, SIGNAL(valueChanged(double)), this, SLOT(handleNormWordTracking()) );
 	connect(minGlyphExtSpinBox     , SIGNAL(valueChanged(double)), this, SLOT(handleMinGlyphExtension()) );
 	connect(maxGlyphExtSpinBox     , SIGNAL(valueChanged(double)), this, SLOT(handleMaxGlyphExtension()) );
+    connect(fallBackFont			, SIGNAL(activated(const QString &)), this, SLOT(handleFontFallBack(const QString &)));
+    connect(fontFallBackSize, SIGNAL(valueChanged(double)), this, SLOT(handleFontFallBackSize(double)));
 }
 
 void PropertyWidget_Advanced::disconnectSignals()
@@ -140,6 +149,8 @@ void PropertyWidget_Advanced::disconnectSignals()
 	disconnect(normWordTrackingSpinBox, SIGNAL(valueChanged(double)), this, SLOT(handleNormWordTracking()) );
 	disconnect(minGlyphExtSpinBox     , SIGNAL(valueChanged(double)), this, SLOT(handleMinGlyphExtension()) );
 	disconnect(maxGlyphExtSpinBox     , SIGNAL(valueChanged(double)), this, SLOT(handleMaxGlyphExtension()) );
+    disconnect(fallBackFont			, SIGNAL(activated(const QString &)), this, SLOT(handleFontFallBack(const QString &)) );
+    disconnect(fontFallBackSize		, SIGNAL(valueChanged(double)), this, SLOT(handleFontFallBackSize(double)));
 }
 
 void PropertyWidget_Advanced::configureWidgets(void)
@@ -197,6 +208,26 @@ void PropertyWidget_Advanced::showTracking(double e)
 	tracking->showValue(e / 10.0);
 }
 
+void PropertyWidget_Advanced::showFontFallBack(const QString &font)
+{
+    if (!m_ScMW || !m_item || m_ScMW->scriptIsRunning())
+        return;
+    if (m_item->itemText.fallBackFont().isEmpty())
+        setCurrentComboItem(fallBackFont, font);
+    else
+        setCurrentComboItem(fallBackFont, m_item->itemText.fallBackFont());
+}
+
+void PropertyWidget_Advanced::showFontFallBackSize(double s)
+{
+    if (!m_ScMW || !m_item || m_ScMW->scriptIsRunning())
+        return;
+    if (m_item->itemText.fallBackFontSize() != 0)
+        fontFallBackSize->showValue(m_item->itemText.fallBackFontSize());
+    else
+        fontFallBackSize->showValue(s / 10.0);
+}
+
 void PropertyWidget_Advanced::handleBaselineOffset()
 {
 	if (!m_doc || !m_item || !m_ScMW || m_ScMW->scriptIsRunning())
@@ -325,6 +356,50 @@ void PropertyWidget_Advanced::handleTracking()
 	}
 }
 
+void PropertyWidget_Advanced::handleFontFallBack(const QString &font)
+{
+    if (!m_doc || !m_item || !m_ScMW || m_ScMW->scriptIsRunning())
+        return;
+    m_item->itemText.setFallBackFont(font);
+    if (m_missingfaceslist.isEmpty())
+        m_missingfaceslist = m_item->itemText.missingFaces();
+
+    if (!m_missingfaceslist.isEmpty())
+    {
+        CharStyle charStyle;
+        charStyle.setFont((*m_doc->AllFonts)[font]);
+
+        foreach (const GlyphCluster& textRun, m_missingfaceslist) {
+            m_item->itemText.applyCharStyle(textRun.firstChar(), textRun.lastChar() - textRun.firstChar() + 1, charStyle);
+        }
+
+        m_item->itemText.invalidateAll();
+        m_doc->changed();
+        m_doc->regionsChanged()->update(QRectF());
+    }
+
+}
+
+void PropertyWidget_Advanced::handleFontFallBackSize(double s)
+{
+    if (!m_doc || !m_item || !m_ScMW || m_ScMW->scriptIsRunning())
+        return;
+    m_item->itemText.setFallBackFontSize(s);
+    if (!m_missingfaceslist.isEmpty())
+    {
+        CharStyle charStyle;
+        charStyle.setFontSize(qRound(fontFallBackSize->value() * 10.0));
+
+        foreach (const GlyphCluster& textRun, m_missingfaceslist) {
+            m_item->itemText.applyCharStyle(textRun.firstChar(), textRun.lastChar() - textRun.firstChar() + 1, charStyle);
+        }
+
+        m_item->itemText.invalidateAll();
+        m_doc->changed();
+        m_doc->regionsChanged()->update(QRectF());
+    }
+}
+
 void PropertyWidget_Advanced::updateCharStyle(const CharStyle& charStyle)
 {
 	if (!m_ScMW || m_ScMW->scriptIsRunning())
@@ -334,6 +409,8 @@ void PropertyWidget_Advanced::updateCharStyle(const CharStyle& charStyle)
 	showTextScaleV(charStyle.scaleV());
 	showTracking(charStyle.tracking());
 	showBaseLineOffset(charStyle.baselineOffset());
+    showFontFallBack(charStyle.font().family() + " " + charStyle.font().style());
+    showFontFallBackSize(charStyle.fontSize());
 
 	normWordTrackingSpinBox->showValue(charStyle.wordTracking() * 100.0);
 }
diff --git a/scribus/ui/propertywidget_advanced.h b/scribus/ui/propertywidget_advanced.h
index 2ab15fa..6bf468a 100644
--- a/scribus/ui/propertywidget_advanced.h
+++ b/scribus/ui/propertywidget_advanced.h
@@ -8,8 +8,8 @@ for which a new license (GPL+exception) is in place.
 #define PROPERTYWIDGET_ADVANCED_H
 
 #include "ui_propertywidget_advancedbase.h"
-
 #include "propertywidgetbase.h"
+#include "text/glyphcluster.h"
 
 class CharStyle;
 class ParagraphStyle;
@@ -53,6 +53,8 @@ public slots:
 	void showTextScaleH(double e);
 	void showTextScaleV(double e);
 	void showTracking(double e);
+    void showFontFallBack(const QString& font);
+    void showFontFallBackSize(double s);
 
 	void updateCharStyle(const CharStyle& charStyle);
 	void updateStyle(const ParagraphStyle& newCurrent);
@@ -66,7 +68,10 @@ private slots:
 	void handleTextScaleH();
 	void handleTextScaleV();
 	void handleTracking();
-
+    void handleFontFallBack(const QString &font);
+   void handleFontFallBackSize(double s);
+private:
+   QList<GlyphCluster> m_missingfaceslist;
 };
 
 #endif
diff --git a/scribus/ui/propertywidget_advancedbase.ui b/scribus/ui/propertywidget_advancedbase.ui
index baafb21..cbf6109 100644
--- a/scribus/ui/propertywidget_advancedbase.ui
+++ b/scribus/ui/propertywidget_advancedbase.ui
@@ -6,8 +6,8 @@
    <rect>
     <x>0</x>
     <y>0</y>
-    <width>239</width>
-    <height>155</height>
+    <width>252</width>
+    <height>269</height>
    </rect>
   </property>
   <property name="windowTitle">
@@ -227,6 +227,27 @@
      </property>
     </widget>
    </item>
+   <item row="6" column="0" colspan="2">
+    <widget class="QLabel" name="fontFallBackLabel">
+     <property name="text">
+      <string>Font Fallback</string>
+     </property>
+    </widget>
+   </item>
+   <item row="7" column="0" colspan="3">
+    <widget class="FontCombo" name="fallBackFont" native="true">
+     <property name="toolTip">
+      <string>Set Fallback Font fot the Text Frame</string>
+     </property>
+    </widget>
+   </item>
+   <item row="8" column="0" colspan="3">
+    <widget class="ScrSpinBox" name="fontFallBackSize">
+     <property name="toolTip">
+      <string>Set Font Size for font Fallback</string>
+     </property>
+    </widget>
+   </item>
   </layout>
  </widget>
  <customwidgets>
@@ -235,6 +256,11 @@
    <extends>QDoubleSpinBox</extends>
    <header>ui/scrspinbox.h</header>
   </customwidget>
+  <customwidget>
+   <class>FontCombo</class>
+   <extends>QWidget</extends>
+   <header>ui/fontcombo.h</header>
+  </customwidget>
  </customwidgets>
  <resources/>
  <connections/>
basicFontsubstitute.patch (12,520 bytes)

Issue History

Date Modified Username Field Change
2010-12-23 04:02 jiero New Issue
2010-12-23 04:04 christoph_s Assigned To => pierremarchand
2010-12-23 04:04 christoph_s Status new => assigned
2010-12-23 07:14 ale Note Added: 0025182
2010-12-26 09:55 jiero Note Added: 0025206
2010-12-27 09:56 jiero Note Added: 0025212
2016-04-01 13:43 Kunda Tag Attached: scribusctl
2016-04-11 19:33 Kunda Note Added: 0040087
2016-04-11 19:34 Kunda Tag Attached: CJK
2016-12-09 17:06 Kunda Target Version => 1.5.3
2016-12-09 17:06 Kunda Patch => No
2017-05-23 21:06 cbradney Target Version 1.5.3 => 1.5.4
2018-05-15 06:49 Fahad File Added: basicFontsubstitute.patch
2018-05-15 06:49 Fahad Note Added: 0045244