API  0.9.8
 All Classes Files Functions Variables Typedefs Macros Groups Pages
CPFontManager.j
Go to the documentation of this file.
1 /*
2  * CPFontManager.j
3  * AppKit
4  *
5  * Created by Tom Robinson.
6  * Copyright 2008, 280 North, Inc.
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public
10  * License as published by the Free Software Foundation; either
11  * version 2.1 of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16  * Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with this library; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21  */
22 
23 
24 
25 @global CPApp
26 
28 CPBoldFontMask = 1 << 1;
39 
40 
43 
47 @implementation CPFontManager : CPObject
48 {
49  CPArray _availableFonts;
50 
51  id _target;
52  SEL _action;
53 
54  id _delegate;
55 
56  CPFont _selectedFont;
57  BOOL _multiple;
58 
59  CPDictionary _activeChange;
60 }
61 
62 // Getting the Shared Font Manager
67 + (CPFontManager)sharedFontManager
68 {
70  CPSharedFontManager = [[CPFontManagerFactory alloc] init];
71 
72  return CPSharedFontManager;
73 }
74 
75 // Changing the Default Font Conversion Classes
80 + (void)setFontManagerFactory:(Class)aClass
81 {
82  CPFontManagerFactory = aClass;
83 }
84 
85 - (id)init
86 {
87  if (self = [super init])
88  {
89  _action = @selector(changeFont:);
90  }
91 
92  return self;
93 }
94 
98 - (CPArray)availableFonts
99 {
100  if (!_availableFonts)
101  {
102  _availableFonts = [];
103 
104 #if PLATFORM(DOM)
105  _CPFontDetectSpan = document.createElement("span");
106  _CPFontDetectSpan.fontSize = "24px";
107  _CPFontDetectSpan.appendChild(document.createTextNode("mmmmmmmmmml"));
108  var div = document.createElement("div");
109  div.style.position = "absolute";
110  div.style.top = "-1000px";
111  div.appendChild(_CPFontDetectSpan);
112  document.getElementsByTagName("body")[0].appendChild(div);
113 
114  _CPFontDetectReferenceFonts = _CPFontDetectPickTwoDifferentFonts(["monospace", "serif", "sans-serif", "cursive"]);
115 
116  for (var i = 0; i < _CPFontDetectAllFonts.length; i++)
117  {
118  var available = _CPFontDetectFontAvailable(_CPFontDetectAllFonts[i]);
119  if (available)
120  _availableFonts.push(_CPFontDetectAllFonts[i]);
121  }
122 #else
123  // If there's no font detection, just assume all fonts are available.
124  _availableFonts = _CPFontDetectAllFonts;
125 #endif
126  }
127  return _availableFonts;
128 }
129 
134 - (CPArray)fontWithNameIsAvailable:(CPString)aFontName
135 {
136  return _CPFontDetectFontAvailable(aFontName);
137 }
138 
139 - (void)setSelectedFont:(CPFont)aFont isMultiple:(BOOL)aFlag
140 {
141  _selectedFont = aFont;
142  _multiple = aFlag;
143 
144  // TODO Notify CPFontPanel when it exists.
145 }
146 
147 - (CPFont)selectedFont
148 {
149  return _selectedFont;
150 }
151 
152 - (int)weightOfFont:(CPFont)aFont
153 {
154  // TODO Weight 5 is a normal of book weight and 9 and above is bold, but it would be nice to be more
155  // precise than that.
156  return [aFont isBold] ? 9 : 5;
157 }
158 
159 - (CPFontTraitMask)traitsOfFont:(CPFont)aFont
160 {
161  return ([aFont isBold] ? CPBoldFontMask : 0) | ([aFont isItalic] ? CPItalicFontMask : 0);
162 }
163 
164 - (CPFont)convertFont:(CPFont)aFont
165 {
166  if (!_activeChange)
167  return aFont;
168 
169  var addTraits = [_activeChange valueForKey:@"addTraits"];
170 
171  if (addTraits)
172  aFont = [self convertFont:aFont toHaveTrait:addTraits];
173 
174  return aFont;
175 }
176 
177 - (CPFont)convertFont:(CPFont)aFont toHaveTrait:(CPFontTraitMask)addTraits
178 {
179  if (!aFont)
180  return nil;
181 
182  var shouldBeBold = ([aFont isBold] || (addTraits & CPBoldFontMask)) && !(addTraits & CPUnboldFontMask),
183  shouldBeItalic = ([aFont isItalic] || (addTraits & CPItalicFontMask)) && !(addTraits & CPUnitalicFontMask),
184  shouldBeSize = [aFont size];
185 
186  // XXX On the current platform there will always be a bold/italic version of each font, but still leave
187  // || aFont in here for future platforms.
188  aFont = [CPFont _fontWithName:[aFont familyName] size:shouldBeSize bold:shouldBeBold italic:shouldBeItalic] || aFont;
189 
190  return aFont;
191 }
192 
193 - (CPFont)convertFont:(CPFont)aFont toFace:(CPString)aTypeface
194 {
195  if (!aFont)
196  return nil;
197 
198  var shouldBeBold = [aFont isBold],
199  shouldBeItalic = [aFont isItalic],
200  shouldBeSize = [aFont size];
201 
202  aFont = [CPFont _fontWithName:aTypeface size:shouldBeSize bold:shouldBeBold italic:shouldBeItalic] || aFont;
203 
204  return aFont;
205 }
206 
207 - (@action)addFontTrait:(id)sender
208 {
209  var tag = [sender tag];
210  _activeChange = tag === nil ? @{} : @{ @"addTraits": tag };
211 
212  [self sendAction];
213 }
214 
215 - (BOOL)sendAction
216 {
217  return [CPApp sendAction:_action to:_target from:self];
218 }
219 
220 @end
221 
222 var _CPFontDetectSpan,
223  _CPFontDetectReferenceFonts,
224  _CPFontDetectAllFonts = /* "04b_21", "A Charming Font", "Abadi MT Condensed", "Abadi MT Condensed Extra Bold", "Abadi MT Condensed Light", "Academy Engraved LET", "Agency FB", "Alba", "Alba Matter", "Alba Super", "Algerian",*//* "Andale Mono", "Andale Mono IPA", "Andy", *//* "Avant Garde", "Avantgarde", "Baby Kruffy", "Base 02", "Baskerville", "Baskerville Old Face", "Bauhaus 93", "Beesknees ITC", "Bell MT", "Berlin Sans FB", "Berlin Sans FB Demi", "Bernard MT Condensed", "Bickley Script",*//* "Blackadder ITC", "Blackletter686 BT", "Bodoni MT", "Bodoni MT Black", "Bodoni MT Condensed", "Bodoni MT Poster Compressed", "Book Antiqua", "Bookman", "Bookman Old Style", "Bradley Hand ITC", "Braggadocio", "Britannic Bold", "Broadway", "Broadway BT",*//* "BudHand", "CAMPBELL", "Calibri", "Californian FB", "Calisto MT", "Calligraph421 BT",*//* "Candara", "Capitals",*//* "Champignon", "Charcoal", "Charter", "Charter BT", "Chicago", "Chick", "Chiller", "ClearlyU", "Colonna MT",*//* "Croobie", "Curlz MT", "Desdemona", "Didot", "DomBold BT", "Edwardian Script ITC", "Engravers MT", "Eras Bold ITC", "Eras Demi ITC", "Eras Light ITC", "Eras Medium ITC", "Eurostile", "FIRSTHOME", "Fat", "Felix Titling", "Fine Hand", "Fixed", "Footlight MT Light", "Forte", "Franklin Gothic Book", "Franklin Gothic Demi", "Franklin Gothic Demi Cond", "Franklin Gothic Heavy", "Franklin Gothic Medium", "Franklin Gothic Medium Cond", "Freestyle Script", "French Script MT", "Freshbot", "Frosty",*//* "GENUINE", "Gadget", "Garamond",*//* "GlooGun", "Gloucester MT Extra Condensed", "Goudy Old Style", "Goudy Stout", "Haettenschweiler", "Harlow Solid Italic", "Harrington",*//* "Informal Roman", "Jenkins v2.0", "John Handy LET", "Jokerman", "Jokerman LET", "Jokewood", "Juice ITC", "Kabel Ult BT", "Kartika", "Kino MT", "Kristen ITC", "Kunstler Script", "La Bamba LET", *//* "Luxi Mono", "Luxi Sans", "Luxi Serif", "MARKETPRO", "MS Reference Sans Serif", "MS Reference Serif", "Magneto", "Maiandra GD", *//* "Matisse ITC", "Matura MT Script Capitals", "Mead Bold", "Mekanik LET", "Mercurius Script MT Bold", *//* "Niagara Engraved", "Niagara Solid", "Nimbus Mono L", "Nimbus Roman No9 L", "OCR A Extended", "OCRB", "Odessa LET", "Old English Text MT", "OldDreadfulNo7 BT", "One Stroke Script LET", "Onyx", "Optima", "Orange LET", "Palace Script MT", "Palatino", "Palatino Linotype", *//* "ParkAvenue BT", "Pepita MT", "Perpetua", "Perpetua Titling MT", "Placard Condensed", "Playbill", "Poornut", "Pristina", "Pump Demi Bold LET", "Pussycat", "Quixley LET", "Rage Italic", "Rage Italic LET", "Ravie", "Rockwell", "Rockwell Condensed", "Rockwell Extra Bold", "Ruach LET", "Runic MT Condensed", "Sand", "Script MT Bold", "Scruff LET", "Segoe UI", "Showcard Gothic", "Skia", "Smudger LET", "Snap ITC", "Square721 BT", "Staccato222 BT", "Stencil", "Sylfaen", *//* "Tw Cen MT", "Tw Cen MT Condensed", "Tw Cen MT Condensed Extra Bold", "URW Antiqua T", "URW Bookman L", "URW Chancery L", "URW Gothic L", "URW Palladio L", "Univers", "University Roman LET", "Utopia", *//* "Victorian LET", "Viner Hand ITC", "Vivaldi", "Vladimir Script", "Vrinda", "Weltron Urban", "Westwood LET", "Wide Latin", "Zapf Chancery", */[
225 
226  "American Typewriter",
227 
228  "Apple Chancery", "Arial", "Arial Black", "Arial Narrow", "Arial Rounded MT Bold", "Arial Unicode MS",
229 
230  "Big Caslon", "Bitstream Vera Sans", "Bitstream Vera Sans Mono", "Bitstream Vera Serif",
231 
232  "Brush Script MT",
233 
234  "Cambria",
235 
236  "Caslon", "Castellar", "Cataneo BT", "Centaur", "Century Gothic", "Century Schoolbook", "Century Schoolbook L",
237 
238  "Comic Sans", "Comic Sans MS", "Consolas", "Constantia", "Cooper Black", "Copperplate", "Copperplate Gothic Bold", "Copperplate Gothic Light", "Corbel", "Courier", "Courier New",
239 
240  "Futura",
241 
242  "Geneva", "Georgia", "Georgia Ref", "Geeza Pro", "Gigi", "Gill Sans", "Gill Sans MT", "Gill Sans MT Condensed", "Gill Sans MT Ext Condensed Bold", "Gill Sans Ultra Bold", "Gill Sans Ultra Bold Condensed",
243 
244  "Helvetica", "Helvetica Narrow", "Helvetica Neue", "Herculanum", "High Tower Text", "Highlight LET", "Hoefler Text", "Impact", "Imprint MT Shadow",
245 
246  "Lucida", "Lucida Bright", "Lucida Calligraphy", "Lucida Console", "Lucida Fax", "Lucida Grande", "Lucida Handwriting", "Lucida Sans", "Lucida Sans Typewriter", "Lucida Sans Unicode",
247 
248  "Marker Felt",
249 
250  "Microsoft Sans Serif", "Milano LET", "Minion Web", "MisterEarl BT", "Mistral", "Monaco", "Monotype Corsiva", "Monotype.com", "New Century Schoolbook", "New York", "News Gothic MT",
251 
252  "Papyrus",
253 
254  "Tahoma", "Techno", "Tempus Sans ITC", "Terminal", "Textile", "Times", "Times New Roman", "Tiranti Solid LET", "Trebuchet MS",
255 
256  "Verdana", "Verdana Ref",
257  "Zapfino"];
258 
259 // Compare against the reference fonts. Return true if it produces a different size than at least one of them.
260 var _CPFontDetectFontAvailable = function(font)
261 {
262  for (var i = 0; i < _CPFontDetectReferenceFonts.length; i++)
263  if (_CPFontDetectCompareFonts(_CPFontDetectReferenceFonts[i], font))
264  return true;
265  return false;
266 };
267 
268 var _CPFontDetectCache = {};
269 
270 // Compares two given fonts. Returns true if they produce different sizes (i.e. fontA didn't fallback to fontB)
271 var _CPFontDetectCompareFonts = function(fontA, fontB)
272 {
273  var a;
274  if (_CPFontDetectCache[fontA])
275  a = _CPFontDetectCache[fontA];
276 
277  else
278  {
279  _CPFontDetectSpan.style.fontFamily = '"' + fontA + '"';
280  _CPFontDetectCache[fontA] = a = { w: _CPFontDetectSpan.offsetWidth, h: _CPFontDetectSpan.offsetHeight };
281  }
282 
283  _CPFontDetectSpan.style.fontFamily = '"' + fontB + '", "' + fontA + '"';
284  var bWidth = _CPFontDetectSpan.offsetWidth,
285  bHeight = _CPFontDetectSpan.offsetHeight;
286 
287  return (a.w != bWidth || a.h != bHeight);
288 };
289 
290 // Test the candidate fonts pairwise until we find two that are different. Otherwise return the first.
291 var _CPFontDetectPickTwoDifferentFonts = function(candidates)
292 {
293  for (var i = 0; i < candidates.length; i++)
294  for (var j = 0; j < i; j++)
295  if (_CPFontDetectCompareFonts(candidates[i], candidates[j]))
296  return [candidates[i], candidates[j]];
297  return [candidates[0]];
298 };
299 
301 
303 
307 - (id)target
308 {
309  return _target;
310 }
311 
315 - (void)setTarget:(id)aValue
316 {
317  _target = aValue;
318 }
319 
323 - (SEL)action
324 {
325  return _action;
326 }
327 
331 - (void)setAction:(SEL)aValue
332 {
333  _action = aValue;
334 }
335 
339 - (id)delegate
340 {
341  return _delegate;
342 }
343 
347 - (void)setDelegate:(id)aValue
348 {
349  _delegate = aValue;
350 }
351 
355 - (BOOL)isMultiple
356 {
357  return _multiple;
358 }
359 
363 - (void)setMultiple:(BOOL)aValue
364 {
365  _multiple = aValue;
366 }
367 
368 @end