KiCad PCB EDA Suite
Loading...
Searching...
No Matches
stroke_font.cpp
Go to the documentation of this file.
1/*
2 * This program source code file is part of KICAD, a free EDA CAD application.
3 *
4 * Copyright (C) 2012 Torsten Hueter, torstenhtr <at> gmx.de
5 * Copyright (C) 2013 CERN
6 * @author Maciej Suminski <[email protected]>
7 * Copyright The KiCad Developers, see AUTHORS.txt for contributors.
8 *
9 * This program is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU General Public License
11 * as published by the Free Software Foundation; either version 2
12 * of the License, or (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program. If not, see <https://www.gnu.org/licenses/>.
21 */
22
24#include <wx/string.h>
25#include <wx/textfile.h>
26#include <newstroke_font.h>
27#include <font/glyph.h>
28#include <font/stroke_font.h>
30#include <trigo.h>
31
32// The "official" name of the building Kicad stroke font (always existing)
34
35#include <mutex>
36
37using namespace KIFONT;
38
39
41static constexpr double STROKE_FONT_SCALE = 1.0 / 21.0;
42
44static constexpr int FONT_OFFSET = -8;
45
46
48std::vector<std::shared_ptr<GLYPH>> g_defaultFontGlyphs;
51
52
54 m_glyphs( nullptr ),
55 m_glyphBoundingBoxes( nullptr ),
56 m_maxGlyphWidth( 0.0 )
57{
58}
59
60
61STROKE_FONT* STROKE_FONT::LoadFont( const wxString& aFontName )
62{
63 if( aFontName.empty() )
64 {
65 STROKE_FONT* font = new STROKE_FONT();
67 return font;
68 }
69 else
70 {
71 // If we ever supported other stroke fonts, the code would go here.
72 return nullptr;
73 }
74}
75
76
77void buildGlyphBoundingBox( std::shared_ptr<STROKE_GLYPH>& aGlyph, double aGlyphWidth )
78{
79 VECTOR2D min( 0, 0 );
80 VECTOR2D max( aGlyphWidth, 0 );
81
82 for( const std::vector<VECTOR2D>& pointList : *aGlyph )
83 {
84 for( const VECTOR2D& point : pointList )
85 {
86 min.y = std::min( min.y, point.y );
87 max.y = std::max( max.y, point.y );
88 }
89 }
90
91 aGlyph->SetBoundingBox( BOX2D( min, max - min ) );
92}
93
94
95void STROKE_FONT::loadNewStrokeFont( const char* const aNewStrokeFont[], int aNewStrokeFontSize )
96{
97 // Protect the initialization sequence against multiple entries
98 std::lock_guard<std::mutex> lock( g_defaultFontLoadMutex );
99
101 {
102 g_defaultFontGlyphs.reserve( aNewStrokeFontSize );
103
104 g_defaultFontGlyphBoundingBoxes = new std::vector<BOX2D>;
105 g_defaultFontGlyphBoundingBoxes->reserve( aNewStrokeFontSize );
106
107 for( int j = 0; j < aNewStrokeFontSize; j++ )
108 {
109 std::shared_ptr<STROKE_GLYPH> glyph = std::make_shared<STROKE_GLYPH>();
110
111 double glyphStartX = 0.0;
112 double glyphEndX = 0.0;
113 double glyphWidth = 0.0;
114 int strokes = 0;
115 int i = 0;
116
117 while( aNewStrokeFont[j][i] )
118 {
119 if( aNewStrokeFont[j][i] == ' ' && aNewStrokeFont[j][i+1] == 'R' )
120 strokes++;
121
122 i += 2;
123 }
124
125 glyph->reserve( strokes + 1 );
126
127 i = 0;
128
129 while( aNewStrokeFont[j][i] )
130 {
131 VECTOR2D point( 0.0, 0.0 );
132 char coordinate[2] = { 0, };
133
134 for( int k : { 0, 1 } )
135 coordinate[k] = aNewStrokeFont[j][i + k];
136
137 if( i < 2 )
138 {
139 // The first two values contain the width of the char
140 glyphStartX = ( coordinate[0] - 'R' ) * STROKE_FONT_SCALE;
141 glyphEndX = ( coordinate[1] - 'R' ) * STROKE_FONT_SCALE;
142 glyphWidth = glyphEndX - glyphStartX;
143 }
144 else if( ( coordinate[0] == ' ' ) && ( coordinate[1] == 'R' ) )
145 {
146 glyph->RaisePen();
147 }
148 else
149 {
150 // In stroke font, coordinates values are coded as <value> + 'R', where
151 // <value> is an ASCII char.
152 // therefore every coordinate description of the Hershey format has an offset,
153 // it has to be subtracted
154 // Note:
155 // * the stroke coordinates are stored in reduced form (-1.0 to +1.0),
156 // and the actual size is stroke coordinate * glyph size
157 // * a few shapes have a height slightly bigger than 1.0 ( like '{' '[' )
158 point.x = (double) ( coordinate[0] - 'R' ) * STROKE_FONT_SCALE - glyphStartX;
159
160 // FONT_OFFSET is here for historical reasons, due to the way the stroke font
161 // was built. It allows shapes coordinates like W M ... to be >= 0
162 // Only shapes like j y have coordinates < 0
163 point.y = (double) ( coordinate[1] - 'R' + FONT_OFFSET ) * STROKE_FONT_SCALE;
164
165 glyph->AddPoint( point );
166 }
167
168 i += 2;
169 }
170
171 glyph->Finalize();
172
173 // Compute the bounding box of the glyph
174 buildGlyphBoundingBox( glyph, glyphWidth );
175 g_defaultFontGlyphBoundingBoxes->emplace_back( glyph->BoundingBox() );
176 g_defaultFontGlyphs.push_back( glyph );
177 m_maxGlyphWidth = std::max( m_maxGlyphWidth, glyphWidth );
178 }
179
181 }
182
186 m_fontFileName = wxEmptyString;
187}
188
189
190double STROKE_FONT::GetInterline( double aGlyphHeight, const METRICS& aFontMetrics ) const
191{
192 static double LEGACY_FACTOR = 0.9583; // Adjustment to match legacy spacing
193
194 return aFontMetrics.GetInterline( aGlyphHeight ) * LEGACY_FACTOR;
195}
196
197
198VECTOR2I STROKE_FONT::GetTextAsGlyphs( BOX2I* aBBox, std::vector<std::unique_ptr<GLYPH>>* aGlyphs,
199 const wxString& aText, const VECTOR2I& aSize,
200 const VECTOR2I& aPosition, const EDA_ANGLE& aAngle,
201 bool aMirror, const VECTOR2I& aOrigin,
202 TEXT_STYLE_FLAGS aTextStyle ) const
203{
204 constexpr int TAB_WIDTH = 4;
205 constexpr double INTER_CHAR = 0.2;
206
207 VECTOR2I cursor( aPosition );
208 VECTOR2D glyphSize( aSize );
209 double tilt = ( aTextStyle & TEXT_STYLE::ITALIC ) ? ITALIC_TILT : 0.0;
210 double space_width = m_glyphBoundingBoxes->front().GetWidth(); // First char is space
211 int char_count = 0;
212
213 if( aTextStyle & TEXT_STYLE::SUBSCRIPT || aTextStyle & TEXT_STYLE::SUPERSCRIPT )
214 {
215 glyphSize = glyphSize * GetSuperSubSizeMultiplier();
216 cursor.y += glyphSize.y * GetSuperSubBaselineOffset( aTextStyle );
217 }
218
219 for( wxUniChar c : aText )
220 {
221 // Handle tabs as locked to the next 4th column (in base-widths).
222 if( c == '\t' )
223 {
224 char_count = ( char_count / TAB_WIDTH + 1 ) * TAB_WIDTH - 1;
225
226 int new_cursor = aPosition.x + aSize.x * char_count
227 + aSize.x * space_width;
228
229 while( new_cursor <= cursor.x )
230 {
231 char_count += TAB_WIDTH;
232 new_cursor += aSize.x * TAB_WIDTH;
233 }
234
235 cursor.x = new_cursor;
236 }
237 else if( c == ' ' )
238 {
239 // 'space' character - draw nothing, advance cursor position
240 cursor.x += KiROUND( glyphSize.x * space_width );
241 }
242 else
243 {
244 // dd is the index into bounding boxes table
245 int dd = (signed) c - ' ';
246
247 // Filtering non existing glyphs and non printable chars
248 if( dd < 0 || dd >= (int) m_glyphBoundingBoxes->size() )
249 {
250 c = '?';
251 dd = (signed) c - ' ';
252 }
253
254 STROKE_GLYPH* source = static_cast<STROKE_GLYPH*>( m_glyphs->at( dd ).get() );
255
256 if( aGlyphs )
257 {
258 aGlyphs->push_back( source->Transform( glyphSize, cursor, tilt, aAngle, aMirror,
259 aOrigin ) );
260 }
261
262 VECTOR2D glyphExtents = source->BoundingBox().GetEnd();
263
264 glyphExtents *= glyphSize;
265
266 cursor.x += KiROUND( glyphExtents.x );
267 }
268
269 ++char_count;
270 }
271
272 if( aBBox )
273 {
274 aBBox->SetOrigin( aPosition );
275 aBBox->SetEnd( cursor.x - KiROUND( glyphSize.x * INTER_CHAR ), cursor.y - glyphSize.y );
276 aBBox->Normalize();
277 }
278
279 return VECTOR2I( cursor.x, aPosition.y );
280}
281
282
284{
285 return m_glyphs ? m_glyphs->size() : 0;
286}
287
288
289const STROKE_GLYPH* STROKE_FONT::GetGlyph( unsigned aIndex ) const
290{
291 if( !m_glyphs || aIndex >= m_glyphs->size() )
292 return nullptr;
293
294 return static_cast<const STROKE_GLYPH*>( m_glyphs->at( aIndex ).get() );
295}
296
297
298const BOX2D& STROKE_FONT::GetGlyphBoundingBox( unsigned aIndex ) const
299{
300 static const BOX2D empty;
301
302 if( !m_glyphBoundingBoxes || aIndex >= m_glyphBoundingBoxes->size() )
303 return empty;
304
305 return m_glyphBoundingBoxes->at( aIndex );
306}
BOX2< VECTOR2I > BOX2I
Definition box2.h:914
constexpr BOX2I KiROUND(const BOX2D &aBoxD)
Definition box2.h:982
BOX2< VECTOR2D > BOX2D
Definition box2.h:915
constexpr void SetOrigin(const Vec &pos)
Definition box2.h:234
constexpr BOX2< Vec > & Normalize()
Ensure that the height and width are positive.
Definition box2.h:143
constexpr void SetEnd(coord_type x, coord_type y)
Definition box2.h:294
wxString m_fontName
Font name.
Definition font.h:285
wxString m_fontFileName
Font file name.
Definition font.h:286
double GetInterline(double aFontHeight) const
double GetInterline(double aGlyphHeight, const METRICS &aFontMetrics) const override
Compute the distance (interline) between 2 lines of text (for multiline texts).
double GetSuperSubBaselineOffset(TEXT_STYLE_FLAGS aTextStyle) const override
Return the baseline shift of a superscript or subscript run, as a downwards fraction of the reduced g...
Definition stroke_font.h:73
double GetSuperSubSizeMultiplier() const override
Return the factor the text size is multiplied by for a superscript or subscript run.
Definition stroke_font.h:71
void loadNewStrokeFont(const char *const aNewStrokeFont[], int aNewStrokeFontSize)
Load the standard KiCad stroke font.
const STROKE_GLYPH * GetGlyph(unsigned aIndex) const
const BOX2D & GetGlyphBoundingBox(unsigned aIndex) const
const std::vector< BOX2D > * m_glyphBoundingBoxes
const std::vector< std::shared_ptr< GLYPH > > * m_glyphs
static STROKE_FONT * LoadFont(const wxString &aFontName)
Load a stroke font.
unsigned GetGlyphCount() const
VECTOR2I GetTextAsGlyphs(BOX2I *aBoundingBox, std::vector< std::unique_ptr< GLYPH > > *aGlyphs, const wxString &aText, const VECTOR2I &aSize, const VECTOR2I &aPosition, const EDA_ANGLE &aAngle, bool aMirror, const VECTOR2I &aOrigin, TEXT_STYLE_FLAGS aTextStyle) const override
Convert text string to an array of GLYPHs.
static bool empty(const wxTextEntryBase *aCtrl)
@ SUBSCRIPT
Definition font.h:45
@ ITALIC
Definition font.h:44
@ SUPERSCRIPT
Definition font.h:46
unsigned int TEXT_STYLE_FLAGS
Definition font.h:61
static constexpr double ITALIC_TILT
Tilt factor for italic style (this is the scaling factor on dY relative coordinates to give a tilted ...
Definition font.h:58
std::string source
#define KICAD_FONT_NAME
const int newstroke_font_bufsize
const char *const newstroke_font[]
Modified 2019 to include based CJK Unicode Ideographs, using code copyright (c) 2018 Lingdong Huang.
static constexpr int FONT_OFFSET
Offset (in stroke font units) to move the origin to the baseline.
std::mutex g_defaultFontLoadMutex
std::vector< std::shared_ptr< GLYPH > > g_defaultFontGlyphs
bool g_defaultFontInitialized
std::vector< BOX2D > * g_defaultFontGlyphBoundingBoxes
void buildGlyphBoundingBox(std::shared_ptr< STROKE_GLYPH > &aGlyph, double aGlyphWidth)
static constexpr double STROKE_FONT_SCALE
Scale factor for a glyph.
VECTOR2< int32_t > VECTOR2I
Definition vector2d.h:708
VECTOR2< double > VECTOR2D
Definition vector2d.h:707