API  0.9.6
 All Classes Files Functions Variables 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 
26 CPBoldFontMask = 1 << 1;
37 
38 
41 
45 @implementation CPFontManager : CPObject
46 {
47  CPArray _availableFonts;
48 
49  id _target;
50  SEL _action;
51 
52  id _delegate;
53 
54  CPFont _selectedFont;
55  BOOL _multiple;
56 
57  CPDictionary _activeChange;
58 }
59 
60 // Getting the Shared Font Manager
65 + (CPFontManager)sharedFontManager
66 {
68  CPSharedFontManager = [[CPFontManagerFactory alloc] init];
69 
70  return CPSharedFontManager;
71 }
72 
73 // Changing the Default Font Conversion Classes
78 + (void)setFontManagerFactory:(Class)aClass
79 {
80  CPFontManagerFactory = aClass;
81 }
82 
83 - (id)init
84 {
85  if (self = [super init])
86  {
87  _action = @selector(changeFont:);
88  }
89 
90  return self;
91 }
92 
96 - (CPArray)availableFonts
97 {
98  if (!_availableFonts)
99  {
100  _availableFonts = [];
101 
102 #if PLATFORM(DOM)
103  _CPFontDetectSpan = document.createElement("span");
104  _CPFontDetectSpan.fontSize = "24px";
105  _CPFontDetectSpan.appendChild(document.createTextNode("mmmmmmmmmml"));
106  var div = document.createElement("div");
107  div.style.position = "absolute";
108  div.style.top = "-1000px";
109  div.appendChild(_CPFontDetectSpan);
110  document.getElementsByTagName("body")[0].appendChild(div);
111 
112  _CPFontDetectReferenceFonts = _CPFontDetectPickTwoDifferentFonts(["monospace", "serif", "sans-serif", "cursive"]);
113 
114  for (var i = 0; i < _CPFontDetectAllFonts.length; i++)
115  {
116  var available = _CPFontDetectFontAvailable(_CPFontDetectAllFonts[i]);
117  if (available)
118  _availableFonts.push(_CPFontDetectAllFonts[i]);
119  }
120 #else
121  // If there's no font detection, just assume all fonts are available.
122  _availableFonts = _CPFontDetectAllFonts;
123 #endif
124  }
125  return _availableFonts;
126 }
127 
132 - (CPArray)fontWithNameIsAvailable:(CPString)aFontName
133 {
134  return _CPFontDetectFontAvailable(aFontName);
135 }
136 
137 - (void)setSelectedFont:(CPFont)aFont isMultiple:(BOOL)aFlag
138 {
139  _selectedFont = aFont;
140  _isMultiple = aFlag;
141 
142  // TODO Notify CPFontPanel when it exists.
143 }
144 
145 - (CPFont)selectedFont
146 {
147  return _selectedFont;
148 }
149 
150 - (BOOL)isMultiple
151 {
152  return _isMultiple;
153 }
154 
155 - (int)weightOfFont:(CPFont)aFont
156 {
157  // TODO Weight 5 is a normal of book weight and 9 and above is bold, but it would be nice to be more
158  // precise than that.
159  return [aFont isBold] ? 9 : 5;
160 }
161 
162 - (CPFontTraitMask)traitsOfFont:(CPFont)aFont
163 {
164  return ([aFont isBold] ? CPBoldFontMask : 0) | ([aFont isItalic] ? CPItalicFontMask : 0);
165 }
166 
167 - (CPFont)convertFont:(CPFont)aFont
168 {
169  if (!_activeChange)
170  return aFont;
171 
172  var addTraits = [_activeChange valueForKey:@"addTraits"];
173 
174  if (addTraits)
175  aFont = [self convertFont:aFont toHaveTrait:addTraits];
176 
177  return aFont;
178 }
179 
180 - (CPFont)convertFont:(CPFont)aFont toHaveTrait:(CPFontTraitMask)addTraits
181 {
182  if (!aFont)
183  return nil;
184 
185  var shouldBeBold = ([aFont isBold] || (addTraits & CPBoldFontMask)) && !(addTraits & CPUnboldFontMask),
186  shouldBeItalic = ([aFont isItalic] || (addTraits & CPItalicFontMask)) && !(addTraits & CPUnitalicFontMask),
187  shouldBeSize = [aFont size];
188 
189  // XXX On the current platform there will always be a bold/italic version of each font, but still leave
190  // || aFont in here for future platforms.
191  aFont = [CPFont _fontWithName:[aFont familyName] size:shouldBeSize bold:shouldBeBold italic:shouldBeItalic] || aFont;
192 
193  return aFont;
194 }
195 
196 - (CPFont)convertFont:(CPFont)aFont toFace:(CPString)aTypeface
197 {
198  if (!aFont)
199  return nil;
200 
201  var shouldBeBold = [aFont isBold],
202  shouldBeItalic = [aFont isItalic],
203  shouldBeSize = [aFont size];
204 
205  aFont = [CPFont _fontWithName:aTypeface size:shouldBeSize bold:shouldBeBold italic:shouldBeItalic] || aFont;
206 
207  return aFont;
208 }
209 
210 - (@action)addFontTrait:(id)sender
211 {
212  _activeChange = [CPDictionary dictionaryWithObject:[sender tag] forKey:@"addTraits"];
213 
214  [self sendAction];
215 }
216 
217 - (BOOL)sendAction
218 {
219  return [CPApp sendAction:_action to:_target from:self];
220 }
221 
222 @end
223 
224 var _CPFontDetectSpan,
225  _CPFontDetectReferenceFonts,
226  _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", */[
227 
228  "American Typewriter",
229 
230  "Apple Chancery", "Arial", "Arial Black", "Arial Narrow", "Arial Rounded MT Bold", "Arial Unicode MS",
231 
232  "Big Caslon", "Bitstream Vera Sans", "Bitstream Vera Sans Mono", "Bitstream Vera Serif",
233 
234  "Brush Script MT",
235 
236  "Cambria",
237 
238  "Caslon", "Castellar", "Cataneo BT", "Centaur", "Century Gothic", "Century Schoolbook", "Century Schoolbook L",
239 
240  "Comic Sans", "Comic Sans MS", "Consolas", "Constantia", "Cooper Black", "Copperplate", "Copperplate Gothic Bold", "Copperplate Gothic Light", "Corbel", "Courier", "Courier New",
241 
242  "Futura",
243 
244  "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",
245 
246  "Helvetica", "Helvetica Narrow", "Helvetica Neue", "Herculanum", "High Tower Text", "Highlight LET", "Hoefler Text", "Impact", "Imprint MT Shadow",
247 
248  "Lucida", "Lucida Bright", "Lucida Calligraphy", "Lucida Console", "Lucida Fax", "Lucida Grande", "Lucida Handwriting", "Lucida Sans", "Lucida Sans Typewriter", "Lucida Sans Unicode",
249 
250  "Marker Felt",
251 
252  "Microsoft Sans Serif", "Milano LET", "Minion Web", "MisterEarl BT", "Mistral", "Monaco", "Monotype Corsiva", "Monotype.com", "New Century Schoolbook", "New York", "News Gothic MT",
253 
254  "Papyrus",
255 
256  "Tahoma", "Techno", "Tempus Sans ITC", "Terminal", "Textile", "Times", "Times New Roman", "Tiranti Solid LET", "Trebuchet MS",
257 
258  "Verdana", "Verdana Ref",
259  "Zapfino"];
260 
261 // Compare against the reference fonts. Return true if it produces a different size than at least one of them.
262 var _CPFontDetectFontAvailable = function(font)
263 {
264  for (var i = 0; i < _CPFontDetectReferenceFonts.length; i++)
265  if (_CPFontDetectCompareFonts(_CPFontDetectReferenceFonts[i], font))
266  return true;
267  return false;
268 };
269 
270 var _CPFontDetectCache = {};
271 
272 // Compares two given fonts. Returns true if they produce different sizes (i.e. fontA didn't fallback to fontB)
273 var _CPFontDetectCompareFonts = function(fontA, fontB)
274 {
275  var a;
276  if (_CPFontDetectCache[fontA])
277  a = _CPFontDetectCache[fontA];
278 
279  else
280  {
281  _CPFontDetectSpan.style.fontFamily = '"' + fontA + '"';
282  _CPFontDetectCache[fontA] = a = { w: _CPFontDetectSpan.offsetWidth, h: _CPFontDetectSpan.offsetHeight };
283  }
284 
285  _CPFontDetectSpan.style.fontFamily = '"' + fontB + '", "' + fontA + '"';
286  var bWidth = _CPFontDetectSpan.offsetWidth,
287  bHeight = _CPFontDetectSpan.offsetHeight;
288 
289  return (a.w != bWidth || a.h != bHeight);
290 };
291 
292 // Test the candidate fonts pairwise until we find two that are different. Otherwise return the first.
293 var _CPFontDetectPickTwoDifferentFonts = function(candidates)
294 {
295  for (var i = 0; i < candidates.length; i++)
296  for (var j = 0; j < i; j++)
297  if (_CPFontDetectCompareFonts(candidates[i], candidates[j]))
298  return [candidates[i], candidates[j]];
299  return [candidates[0]];
300 };
301 
303 
305 
309 - (id)target
310 {
311  return _target;
312 }
313 
317 - (void)setTarget:(id)aValue
318 {
319  _target = aValue;
320 }
321 
325 - (SEL)action
326 {
327  return _action;
328 }
329 
333 - (void)setAction:(SEL)aValue
334 {
335  _action = aValue;
336 }
337 
341 - (id)delegate
342 {
343  return _delegate;
344 }
345 
349 - (void)setDelegate:(id)aValue
350 {
351  _delegate = aValue;
352 }
353 
354 @end