1 /* -*- Mode: C++; c-default-style: "k&r"; indent-tabs-mode: nil; tab-width: 2; c-basic-offset: 2 -*- */
2 
3 /* libmwaw
4 * Version: MPL 2.0 / LGPLv2+
5 *
6 * The contents of this file are subject to the Mozilla Public License Version
7 * 2.0 (the "License"); you may not use this file except in compliance with
8 * the License or as specified alternatively below. You may obtain a copy of
9 * the License at http://www.mozilla.org/MPL/
10 *
11 * Software distributed under the License is distributed on an "AS IS" basis,
12 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
13 * for the specific language governing rights and limitations under the
14 * License.
15 *
16 * Major Contributor(s):
17 * Copyright (C) 2002 William Lachance (wrlach@gmail.com)
18 * Copyright (C) 2002,2004 Marc Maurer (uwog@uwog.net)
19 * Copyright (C) 2004-2006 Fridrich Strba (fridrich.strba@bluewin.ch)
20 * Copyright (C) 2006, 2007 Andrew Ziem
21 * Copyright (C) 2011, 2012 Alonso Laurent (alonso@loria.fr)
22 *
23 *
24 * All Rights Reserved.
25 *
26 * For minor contributions see the git repository.
27 *
28 * Alternatively, the contents of this file may be used under the terms of
29 * the GNU Lesser General Public License Version 2 or later (the "LGPLv2+"),
30 * in which case the provisions of the LGPLv2+ are applicable
31 * instead of those above.
32 */
33 
34 #ifndef MWAW_FONT
35 #  define MWAW_FONT
36 
37 #include <string>
38 #include <vector>
39 
40 #include "libmwaw_internal.hxx"
41 
42 //! Class to store font
43 class MWAWFont
44 {
45 public:
46   /** a small struct to define a line in MWAWFont */
47   struct Line {
48     /** the line style */
49     enum Style { None, Simple, Dot, LargeDot, Dash, Wave };
50     /** the line style */
51     enum Type { Single, Double, Triple };
52     //! constructor
LineMWAWFont::Line53     explicit Line(Style style=None, Type type=Single, bool wordFlag=false, float w=1.0)
54       : m_style(style)
55       , m_type(type)
56       , m_width(w)
57       , m_color(MWAWColor::black())
58       , m_word(wordFlag)
59     {
60     }
61     //! return true if the line is not empty
isSetMWAWFont::Line62     bool isSet() const
63     {
64       return m_style != None && m_width>0;
65     }
66     //! add a line to the propList knowing the type (line-through, underline, overline )
67     void addTo(librevenge::RVNGPropertyList &propList, std::string const &type) const;
68     //! operator<<
69     friend std::ostream &operator<<(std::ostream &o, Line const &line);
70     //! operator==
operator ==MWAWFont::Line71     bool operator==(Line const &oth) const
72     {
73       return cmp(oth)==0;
74     }
75     //! operator!=
operator !=MWAWFont::Line76     bool operator!=(Line const &oth) const
77     {
78       return cmp(oth)!=0;
79     }
80     //! small comparison function
cmpMWAWFont::Line81     int cmp(Line const &oth) const
82     {
83       if (m_style != oth.m_style) return int(m_style)-int(oth.m_style);
84       if (m_type != oth.m_type) return int(m_type)-int(oth.m_type);
85       if (m_word != oth.m_word) return m_word ? -1 : 1;
86       if (m_width < oth.m_width) return -1;
87       if (m_width > oth.m_width) return 1;
88       if (m_color.isSet() != oth.m_color.isSet())
89         return m_color.isSet();
90       if (m_color.get() < oth.m_color.get()) return -1;
91       if (m_color.get() > oth.m_color.get()) return 1;
92       return 0;
93     }
94     /** the style */
95     Style m_style;
96     /** the type */
97     Type m_type;
98     /** the width in point */
99     float m_width;
100     /** the color ( if not set, we use the font color )*/
101     MWAWVariable<MWAWColor> m_color;
102     /** word or not word line */
103     bool m_word;
104   };
105   /** a small struct to define the script position in MWAWFont */
106   struct Script {
107     //! constructor
ScriptMWAWFont::Script108     explicit Script(float delta=0, librevenge::RVNGUnit deltaUnit=librevenge::RVNG_PERCENT, int scale=100)
109       : m_delta(delta)
110       , m_deltaUnit(deltaUnit)
111       , m_scale(scale)
112     {
113     }
114     //! return true if the position is not default
isSetMWAWFont::Script115     bool isSet() const
116     {
117       return *this != Script();
118     }
119     //! return a yposition which correspond to a basic subscript
subMWAWFont::Script120     static Script sub()
121     {
122       return Script(-33,librevenge::RVNG_PERCENT,58);
123     }
124     //! return a yposition which correspond to a basic subscript100
sub100MWAWFont::Script125     static Script sub100()
126     {
127       return Script(-20);
128     }
129     //! return a yposition which correspond to a basic superscript
superMWAWFont::Script130     static Script super()
131     {
132       return Script(33,librevenge::RVNG_PERCENT,58);
133     }
134     //! return a yposition which correspond to a basic superscript100
super100MWAWFont::Script135     static Script super100()
136     {
137       return Script(20);
138     }
139     //! return a string which correspond to style:text-position
140     std::string str(float fSize) const;
141 
142     //! operator==
operator ==MWAWFont::Script143     bool operator==(Script const &oth) const
144     {
145       return cmp(oth)==0;
146     }
147     //! operator!=
operator !=MWAWFont::Script148     bool operator!=(Script const &oth) const
149     {
150       return cmp(oth)!=0;
151     }
152     //! operator<
operator <MWAWFont::Script153     bool operator<(Script const &oth) const
154     {
155       return cmp(oth)<0;
156     }
157     //! operator<=
operator <=MWAWFont::Script158     bool operator<=(Script const &oth) const
159     {
160       return cmp(oth)<=0;
161     }
162     //! operator>
operator >MWAWFont::Script163     bool operator>(Script const &oth) const
164     {
165       return cmp(oth)>0;
166     }
167     //! operator>=
operator >=MWAWFont::Script168     bool operator>=(Script const &oth) const
169     {
170       return cmp(oth)>=0;
171     }
172     //! small comparison function
cmpMWAWFont::Script173     int cmp(Script const &oth) const
174     {
175       if (m_delta > oth.m_delta) return -1;
176       if (m_delta < oth.m_delta) return 1;
177       if (m_deltaUnit != oth.m_deltaUnit) return int(m_deltaUnit)-int(oth.m_deltaUnit);
178       if (m_scale != oth.m_scale) return m_scale-oth.m_scale;
179       return 0;
180     }
181     //! the ydelta
182     float m_delta;
183     //! the ydelta unit ( point or percent )
184     librevenge::RVNGUnit m_deltaUnit;
185     //! the font scaling ( in percent )
186     int m_scale;
187   };
188 
189   //! the different font bit
190   enum FontBits { boldBit=1, italicBit=2, blinkBit=4, embossBit=8, engraveBit=0x10,
191                   hiddenBit=0x20, outlineBit=0x40, shadowBit=0x80,
192                   reverseVideoBit=0x100, smallCapsBit=0x200, uppercaseBit=0x400,
193                   lowercaseBit=0x800,
194                   initialcaseBit=2*lowercaseBit,
195                   boxedBit=2*initialcaseBit,
196                   boxedRoundedBit=2*boxedBit,
197                   reverseWritingBit=2*boxedRoundedBit
198                 };
199   /** constructor
200    *
201    * \param newId system id font
202    * \param sz the font size
203    * \param f the font attributes bold, ... */
MWAWFont(int newId=-1,float sz=12,uint32_t f=0)204   explicit MWAWFont(int newId=-1, float sz=12, uint32_t f = 0)
205     : m_id(newId)
206     , m_size(sz)
207     , m_sizeIsRelative(false)
208     , m_deltaSpacing(0)
209     , m_deltaSpacingUnit(librevenge::RVNG_POINT)
210     , m_widthStreching(1)
211     , m_scriptPosition()
212     , m_flags(f)
213     , m_overline(Line(Line::None))
214     , m_strikeoutline(Line(Line::None))
215     , m_underline(Line(Line::None))
216     , m_color(MWAWColor::black())
217     , m_backgroundColor(MWAWColor::white())
218     , m_language("")
219     , m_extra("")
220   {
221     resetColor();
222   }
223   //! returns true if the font id is initialized
isSet() const224   bool isSet() const
225   {
226     return m_id.isSet();
227   }
228   //! inserts the set value in the current font
insert(MWAWFont const & ft)229   void insert(MWAWFont const &ft)
230   {
231     m_id.insert(ft.m_id);
232     m_size.insert(ft.m_size);
233     m_sizeIsRelative.insert(ft.m_sizeIsRelative);
234     m_deltaSpacing.insert(ft.m_deltaSpacing);
235     m_deltaSpacingUnit.insert(ft.m_deltaSpacingUnit);
236     m_widthStreching.insert(ft.m_widthStreching);
237     m_scriptPosition.insert(ft.m_scriptPosition);
238     if (ft.m_flags.isSet()) {
239       if (m_flags.isSet())
240         setFlags(flags()| ft.flags());
241       else
242         m_flags = ft.m_flags;
243     }
244     m_overline.insert(ft.m_overline);
245     m_strikeoutline.insert(ft.m_strikeoutline);
246     m_underline.insert(ft.m_underline);
247     m_color.insert(ft.m_color);
248     m_backgroundColor.insert(ft.m_backgroundColor);
249     m_extra += ft.m_extra;
250   }
251   //! sets the font id and resets size to the previous size for this font
setFont(int newId)252   void setFont(int newId)
253   {
254     resetColor();
255     m_id=newId;
256   }
257 
258   //! returns the font id
id() const259   int id() const
260   {
261     return m_id.get();
262   }
263   //! sets the font id
setId(int newId)264   void setId(int newId)
265   {
266     m_id = newId;
267   }
268 
269   //! returns the font size
size() const270   float size() const
271   {
272     return m_size.get();
273   }
274   //! sets the font size
setSize(float sz,bool isRelative=false)275   void setSize(float sz, bool isRelative=false)
276   {
277     m_size = sz;
278     m_sizeIsRelative = isRelative;
279   }
280 
281   //! returns the condensed(negative)/extended(positive) width
deltaLetterSpacing() const282   float deltaLetterSpacing() const
283   {
284     return m_deltaSpacing.get();
285   }
286   //! returns the condensed(negative)/extended(positive) unit
deltaLetterSpacingUnit() const287   librevenge::RVNGUnit deltaLetterSpacingUnit() const
288   {
289     return m_deltaSpacingUnit.get();
290   }
291   //! sets the letter spacing ( delta value in point )
setDeltaLetterSpacing(float d,librevenge::RVNGUnit unit=librevenge::RVNG_POINT)292   void setDeltaLetterSpacing(float d, librevenge::RVNGUnit unit=librevenge::RVNG_POINT)
293   {
294     m_deltaSpacing=d;
295     m_deltaSpacingUnit=unit;
296   }
297   //! returns the text width streching
widthStreching() const298   float widthStreching() const
299   {
300     return m_widthStreching.get();
301   }
302   //! sets the text width streching
setWidthStreching(float scale=1.0)303   void setWidthStreching(float scale=1.0)
304   {
305     m_widthStreching = scale;
306   }
307   //! returns the script position
script() const308   Script const &script() const
309   {
310     return m_scriptPosition.get();
311   }
312 
313   //! sets the script position
set(Script const & newscript)314   void set(Script const &newscript)
315   {
316     m_scriptPosition = newscript;
317   }
318 
319   //! returns the font flags
flags() const320   uint32_t flags() const
321   {
322     return m_flags.get();
323   }
324   //! sets the font attributes bold, ...
setFlags(uint32_t fl)325   void setFlags(uint32_t fl)
326   {
327     m_flags = fl;
328   }
329 
330   //! returns true if the font color is not black
hasColor() const331   bool hasColor() const
332   {
333     return m_color.isSet() && !m_color.get().isBlack();
334   }
335   //! returns the font color
getColor(MWAWColor & c) const336   void getColor(MWAWColor &c) const
337   {
338     c = m_color.get();
339   }
340   //! sets the font color
setColor(MWAWColor color)341   void setColor(MWAWColor color)
342   {
343     m_color = color;
344   }
345 
346   //! returns the font background color
getBackgroundColor(MWAWColor & c) const347   void getBackgroundColor(MWAWColor &c) const
348   {
349     c = m_backgroundColor.get();
350   }
351   //! sets the font background color
setBackgroundColor(MWAWColor color)352   void setBackgroundColor(MWAWColor color)
353   {
354     m_backgroundColor = color;
355   }
356   //! resets the font color to black and the background color to white
resetColor()357   void resetColor()
358   {
359     m_color = MWAWColor::black();
360     m_backgroundColor = MWAWColor::white();
361   }
362 
363   //! return true if the font has decorations line (overline, strikeout, underline)
hasDecorationLines() const364   bool hasDecorationLines() const
365   {
366     return (m_overline.isSet() && m_overline->isSet()) ||
367            (m_strikeoutline.isSet() && m_strikeoutline->isSet()) ||
368            (m_underline.isSet() && m_underline->isSet());
369   }
370   //! reset the decoration
resetDecorationLines()371   void resetDecorationLines()
372   {
373     if (m_overline.isSet()) m_overline=Line(Line::None);
374     if (m_strikeoutline.isSet()) m_strikeoutline=Line(Line::None);
375     if (m_underline.isSet()) m_underline=Line(Line::None);
376   }
377   //! returns the overline
getOverline() const378   Line const &getOverline() const
379   {
380     return m_overline.get();
381   }
382   //! sets the overline
setOverline(Line const & line)383   void setOverline(Line const &line)
384   {
385     m_overline = line;
386   }
387   //! sets the overline style ( by default, we also reset the style)
setOverlineStyle(Line::Style style=Line::None,bool doReset=true)388   void setOverlineStyle(Line::Style style=Line::None, bool doReset=true)
389   {
390     if (doReset)
391       m_overline = Line(style);
392     else
393       m_overline->m_style = style;
394   }
395   //! sets the overline type
setOverlineType(Line::Type type=Line::Single)396   void setOverlineType(Line::Type type=Line::Single)
397   {
398     m_overline->m_type = type;
399   }
400   //! sets the overline word flag
setOverlineWordFlag(bool wordFlag=false)401   void setOverlineWordFlag(bool wordFlag=false)
402   {
403     m_overline->m_word = wordFlag;
404   }
405   //! sets the overline width
setOverlineWidth(float w)406   void setOverlineWidth(float w)
407   {
408     m_overline->m_width = w;
409   }
410   //! sets the overline color
setOverlineColor(MWAWColor const & color)411   void setOverlineColor(MWAWColor const &color)
412   {
413     m_overline->m_color = color;
414   }
415 
416   //! returns the strikeoutline
getStrikeOut() const417   Line const &getStrikeOut() const
418   {
419     return m_strikeoutline.get();
420   }
421   //! sets the strikeoutline
setStrikeOut(Line const & line)422   void setStrikeOut(Line const &line)
423   {
424     m_strikeoutline = line;
425   }
426   //! sets the strikeoutline style ( by default, we also reset the style)
setStrikeOutStyle(Line::Style style=Line::None,bool doReset=true)427   void setStrikeOutStyle(Line::Style style=Line::None, bool doReset=true)
428   {
429     if (doReset)
430       m_strikeoutline = Line(style);
431     else
432       m_strikeoutline->m_style = style;
433   }
434   //! sets the strikeoutline type
setStrikeOutType(Line::Type type=Line::Single)435   void setStrikeOutType(Line::Type type=Line::Single)
436   {
437     m_strikeoutline->m_type = type;
438   }
439   //! sets the strikeoutline word flag
setStrikeOutWordFlag(bool wordFlag=false)440   void setStrikeOutWordFlag(bool wordFlag=false)
441   {
442     m_strikeoutline->m_word = wordFlag;
443   }
444   //! sets the strikeoutline width
setStrikeOutWidth(float w)445   void setStrikeOutWidth(float w)
446   {
447     m_strikeoutline->m_width = w;
448   }
449   //! sets the strikeoutline color
setStrikeOutColor(MWAWColor const & color)450   void setStrikeOutColor(MWAWColor const &color)
451   {
452     m_strikeoutline->m_color = color;
453   }
454 
455   //! returns the underline
getUnderline() const456   Line const &getUnderline() const
457   {
458     return m_underline.get();
459   }
460   //! sets the underline
setUnderline(Line const & line)461   void setUnderline(Line const &line)
462   {
463     m_underline = line;
464   }
465   //! sets the underline style ( by default, we also reset the style)
setUnderlineStyle(Line::Style style=Line::None,bool doReset=true)466   void setUnderlineStyle(Line::Style style=Line::None, bool doReset=true)
467   {
468     if (doReset)
469       m_underline = Line(style);
470     else
471       m_underline->m_style = style;
472   }
473   //! sets the underline type
setUnderlineType(Line::Type type=Line::Single)474   void setUnderlineType(Line::Type type=Line::Single)
475   {
476     m_underline->m_type = type;
477   }
478   //! sets the underline word flag
setUnderlineWordFlag(bool wordFlag=false)479   void setUnderlineWordFlag(bool wordFlag=false)
480   {
481     m_underline->m_word = wordFlag;
482   }
483   //! sets the underline width
setUnderlineWidth(float w)484   void setUnderlineWidth(float w)
485   {
486     m_underline->m_width = w;
487   }
488   //! sets the underline color
setUnderlineColor(MWAWColor const & color)489   void setUnderlineColor(MWAWColor const &color)
490   {
491     m_underline->m_color = color;
492   }
493 
494   //! returns the language
language() const495   std::string const &language() const
496   {
497     return m_language.get();
498   }
499   //! set the language ( in the for en_US, en_GB, en, ...)
setLanguage(std::string const & lang)500   void setLanguage(std::string const &lang)
501   {
502     m_language=lang;
503   }
504   //! add to the propList
505   void addTo(librevenge::RVNGPropertyList &propList, std::shared_ptr<MWAWFontConverter> fontConverter) const;
506   //! add to the propList to a list level
507   void addToListLevel(librevenge::RVNGPropertyList &propList, std::shared_ptr<MWAWFontConverter> fontConverter) const;
508 
509   //! returns a string which can be used for debugging
510   std::string getDebugString(std::shared_ptr<MWAWFontConverter> &converter) const;
511 
512   //! operator==
operator ==(MWAWFont const & f) const513   bool operator==(MWAWFont const &f) const
514   {
515     return cmp(f) == 0;
516   }
517   //! operator!=
operator !=(MWAWFont const & f) const518   bool operator!=(MWAWFont const &f) const
519   {
520     return cmp(f) != 0;
521   }
522 
523   //! a comparison function
cmp(MWAWFont const & oth) const524   int cmp(MWAWFont const &oth) const
525   {
526     int diff = id() - oth.id();
527     if (diff != 0) return diff;
528     if (size() < oth.size()) return -1;
529     if (size() > oth.size()) return 1;
530     if (m_sizeIsRelative.get() != oth.m_sizeIsRelative.get()) return m_sizeIsRelative.get() ? 1 : -1;
531     if (flags() < oth.flags()) return -1;
532     if (flags() > oth.flags()) return 1;
533     if (m_deltaSpacing.get() < oth.m_deltaSpacing.get()) return -1;
534     if (m_deltaSpacing.get() > oth.m_deltaSpacing.get()) return 1;
535     if (m_deltaSpacingUnit.get() < oth.m_deltaSpacingUnit.get()) return -1;
536     if (m_deltaSpacingUnit.get() > oth.m_deltaSpacingUnit.get()) return 1;
537     if (m_widthStreching.get() < oth.m_widthStreching.get()) return -1;
538     if (m_widthStreching.get() > oth.m_widthStreching.get()) return 1;
539     diff = script().cmp(oth.script());
540     if (diff != 0) return diff;
541     diff = m_overline.get().cmp(oth.m_overline.get());
542     if (diff != 0) return diff;
543     diff = m_strikeoutline.get().cmp(oth.m_strikeoutline.get());
544     if (diff != 0) return diff;
545     diff = m_underline.get().cmp(oth.m_underline.get());
546     if (diff != 0) return diff;
547     if (m_color.get() < oth.m_color.get()) return -1;
548     if (m_color.get() > oth.m_color.get()) return 1;
549     if (m_backgroundColor.get() < oth.m_backgroundColor.get()) return -1;
550     if (m_backgroundColor.get() > oth.m_backgroundColor.get()) return 1;
551     if (m_language.get() < oth.m_language.get()) return -1;
552     if (m_language.get() > oth.m_language.get()) return 1;
553     return diff;
554   }
555 
556 protected:
557   MWAWVariable<int> m_id /** font identificator*/;
558   MWAWVariable<float> m_size /** font size */;
559   MWAWVariable<bool> m_sizeIsRelative /** true if the size is percent */;
560   MWAWVariable<float> m_deltaSpacing /** expand(&gt; 0), condensed(&lt; 0) depl*/;
561   MWAWVariable<librevenge::RVNGUnit> m_deltaSpacingUnit /** the delta spacing unit */;
562   MWAWVariable<float> m_widthStreching /** the width streching in percent */;
563   MWAWVariable<Script> m_scriptPosition /** the sub/super script definition */;
564   MWAWVariable<uint32_t> m_flags /** font attributes */;
565   MWAWVariable<Line> m_overline /** overline attributes */;
566   MWAWVariable<Line> m_strikeoutline /** overline attributes */;
567   MWAWVariable<Line> m_underline /** underline attributes */;
568   MWAWVariable<MWAWColor> m_color /** font color */;
569   MWAWVariable<MWAWColor> m_backgroundColor /** font background color */;
570   MWAWVariable<std::string> m_language /** the language if set */;
571 public:
572   //! extra data
573   std::string m_extra;
574 };
575 
576 namespace MWAWFontManagerInternal
577 {
578 struct State;
579 }
580 
581 //! a font manager which can be used to store fonts, ...
582 class MWAWFontManager
583 {
584 public:
585   //! constructor
586   explicit MWAWFontManager(std::shared_ptr<MWAWFontConverter> const &fontConverter);
587   //! destructor
588   ~MWAWFontManager();
589   //! returns a span id which can be used to call the list
590   int getId(MWAWFont const &font);
591   //! returns the font corresponding to an id
592   bool getFont(int id, MWAWFont &font) const;
593   //! returns the font converter
594   std::shared_ptr<MWAWFontConverter> getFontConverter();
595 protected:
596   //! the state
597   std::shared_ptr<MWAWFontManagerInternal::State> m_state;
598 private:
599   MWAWFontManager(MWAWFontManager const &) = delete;
600   MWAWFontManager &operator=(MWAWFontManager const &) = delete;
601 };
602 #endif
603 // vim: set filetype=cpp tabstop=2 shiftwidth=2 cindent autoindent smartindent noexpandtab:
604