From 43ecaa845e9042fda99f8b5e91834e8d4b2c1689 Mon Sep 17 00:00:00 2001 From: Jeremias Maerki Date: Sun, 22 Mar 2009 11:54:39 +0000 Subject: Added a command-line tool to list all configured fonts (org.apache.fop.tools.fontlist.FontListMain). git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/trunk@757172 13f79535-47bb-0310-9956-ffa450edef68 --- .../fop/tools/fontlist/FontListGenerator.java | 115 ++++++++ .../apache/fop/tools/fontlist/FontListMain.java | 305 +++++++++++++++++++++ .../fop/tools/fontlist/FontListSerializer.java | 142 ++++++++++ .../org/apache/fop/tools/fontlist/FontSpec.java | 103 +++++++ .../org/apache/fop/tools/fontlist/fonts2fo.xsl | 200 ++++++++++++++ 5 files changed, 865 insertions(+) create mode 100644 src/java/org/apache/fop/tools/fontlist/FontListGenerator.java create mode 100644 src/java/org/apache/fop/tools/fontlist/FontListMain.java create mode 100644 src/java/org/apache/fop/tools/fontlist/FontListSerializer.java create mode 100644 src/java/org/apache/fop/tools/fontlist/FontSpec.java create mode 100644 src/java/org/apache/fop/tools/fontlist/fonts2fo.xsl (limited to 'src/java/org') diff --git a/src/java/org/apache/fop/tools/fontlist/FontListGenerator.java b/src/java/org/apache/fop/tools/fontlist/FontListGenerator.java new file mode 100644 index 000000000..ce44eee19 --- /dev/null +++ b/src/java/org/apache/fop/tools/fontlist/FontListGenerator.java @@ -0,0 +1,115 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* $Id$ */ + +package org.apache.fop.tools.fontlist; + +import java.util.Collections; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.SortedMap; + +import org.apache.fop.apps.FOPException; +import org.apache.fop.apps.FOUserAgent; +import org.apache.fop.apps.FopFactory; +import org.apache.fop.fonts.FontEventListener; +import org.apache.fop.fonts.FontInfo; +import org.apache.fop.fonts.FontMetrics; +import org.apache.fop.fonts.FontTriplet; +import org.apache.fop.render.intermediate.IFDocumentHandler; +import org.apache.fop.render.intermediate.IFDocumentHandlerConfigurator; + +/** + * Generates a list of available fonts. + */ +public class FontListGenerator { + + /** + * List all fonts configured for a particular output format (identified by MIME type). + * The sorted map returned looks like this: + * SortedMap<String/font-family, List<{@link FontSpec}>> + * @param fopFactory the FOP factory (already configured) + * @param mime the MIME type identified the selected output format + * @param listener a font event listener to catch any font-related errors while listing fonts + * @return the map of font families + * @throws FOPException if an error occurs setting up the fonts + */ + public SortedMap listFonts(FopFactory fopFactory, String mime, FontEventListener listener) + throws FOPException { + FontInfo fontInfo = setupFonts(fopFactory, mime, listener); + SortedMap fontFamilies = buildFamilyMap(fontInfo); + return fontFamilies; + } + + private FontInfo setupFonts(FopFactory fopFactory, String mime, FontEventListener listener) + throws FOPException { + FOUserAgent userAgent = fopFactory.newFOUserAgent(); + + //The document handler is only instantiated to get access to its configurator! + IFDocumentHandler documentHandler + = fopFactory.getRendererFactory().createDocumentHandler(userAgent, mime); + IFDocumentHandlerConfigurator configurator = documentHandler.getConfigurator(); + + FontInfo fontInfo = new FontInfo(); + configurator.setupFontInfo(documentHandler, fontInfo); + return fontInfo; + } + + private SortedMap buildFamilyMap(FontInfo fontInfo) { + Map fonts = fontInfo.getFonts(); + Set keyBag = new java.util.HashSet(fonts.keySet()); + + Map keys = new java.util.HashMap(); + SortedMap fontFamilies = new java.util.TreeMap(); + //SortedMap> + + Iterator iter = fontInfo.getFontTriplets().entrySet().iterator(); + while (iter.hasNext()) { + Map.Entry entry = (Map.Entry)iter.next(); + FontTriplet triplet = (FontTriplet)entry.getKey(); + String key = (String)entry.getValue(); + FontSpec container; + if (keyBag.contains(key)) { + keyBag.remove(key); + + FontMetrics metrics = (FontMetrics)fonts.get(key); + + container = new FontSpec(key, metrics); + container.addFamilyNames(metrics.getFamilyNames()); + keys.put(key, container); + String firstFamilyName = (String)container.getFamilyNames().first(); + List containers = (List)fontFamilies.get(firstFamilyName); + if (containers == null) { + containers = new java.util.ArrayList(); + fontFamilies.put(firstFamilyName, containers); + } + containers.add(container); + Collections.sort(containers); + + } else { + container = (FontSpec)keys.get(key); + } + container.addTriplet(triplet); + } + + return fontFamilies; + } + +} diff --git a/src/java/org/apache/fop/tools/fontlist/FontListMain.java b/src/java/org/apache/fop/tools/fontlist/FontListMain.java new file mode 100644 index 000000000..d31da92c2 --- /dev/null +++ b/src/java/org/apache/fop/tools/fontlist/FontListMain.java @@ -0,0 +1,305 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* $Id$ */ + +package org.apache.fop.tools.fontlist; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.OutputStream; +import java.io.PrintStream; +import java.net.URL; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.SortedMap; + +import javax.xml.transform.Transformer; +import javax.xml.transform.TransformerConfigurationException; +import javax.xml.transform.sax.SAXResult; +import javax.xml.transform.sax.SAXTransformerFactory; +import javax.xml.transform.sax.TransformerHandler; +import javax.xml.transform.stream.StreamResult; +import javax.xml.transform.stream.StreamSource; + +import org.xml.sax.ContentHandler; +import org.xml.sax.SAXException; + +import org.apache.commons.io.FilenameUtils; +import org.apache.commons.io.IOUtils; + +import org.apache.fop.Version; +import org.apache.fop.apps.FOPException; +import org.apache.fop.apps.Fop; +import org.apache.fop.apps.FopFactory; +import org.apache.fop.apps.MimeConstants; +import org.apache.fop.fonts.FontEventListener; +import org.apache.fop.fonts.FontTriplet; +import org.apache.fop.util.GenerationHelperContentHandler; + +/** + * Command-line application to list available fonts and to optionally produce sample pages + * with those fonts. + */ +public final class FontListMain { + + private static final int GENERATE_CONSOLE = 0; + private static final int GENERATE_XML = 1; + private static final int GENERATE_FO = 2; + private static final int GENERATE_RENDERED = 3; + + private FopFactory fopFactory = FopFactory.newInstance(); + + private File configFile; + private File outputFile; + private String configMime = MimeConstants.MIME_PDF; + private String outputMime; + private int mode = GENERATE_CONSOLE; + private String singleFamilyFilter; + + private FontListMain() throws SAXException, IOException { + } + + private void prepare() throws SAXException, IOException { + if (this.configFile != null) { + fopFactory.setUserConfig(this.configFile); + } + } + + private ContentHandler getFOPContentHandler(OutputStream out) throws FOPException { + Fop fop = fopFactory.newFop(this.outputMime, out); + return fop.getDefaultHandler(); + } + + private void generateXML(SortedMap fontFamilies, File outFile, String singleFamily) + throws TransformerConfigurationException, SAXException, IOException { + SAXTransformerFactory tFactory = (SAXTransformerFactory)SAXTransformerFactory.newInstance(); + TransformerHandler handler; + if (this.mode == GENERATE_XML) { + handler = tFactory.newTransformerHandler(); + } else { + URL url = getClass().getResource("fonts2fo.xsl"); + if (url == null) { + throw new FileNotFoundException("Did not find resource: fonts2fo.xsl"); + } + handler = tFactory.newTransformerHandler(new StreamSource(url.toExternalForm())); + } + + if (singleFamily != null) { + Transformer transformer = handler.getTransformer(); + transformer.setParameter("single-family", singleFamily); + } + + OutputStream out = new java.io.FileOutputStream(outFile); + out = new java.io.BufferedOutputStream(out); + if (this.mode == GENERATE_RENDERED) { + handler.setResult(new SAXResult(getFOPContentHandler(out))); + } else { + handler.setResult(new StreamResult(out)); + } + try { + GenerationHelperContentHandler helper = new GenerationHelperContentHandler( + handler, null); + FontListSerializer serializer = new FontListSerializer(); + serializer.generateSAX(fontFamilies, singleFamily, helper); + } finally { + IOUtils.closeQuietly(out); + } + } + + private void generate() throws Exception { + prepare(); + + FontEventListener listener = new FontEventListener() { + + public void fontLoadingErrorAtAutoDetection(Object source, + String fontURL, Exception e) { + System.err.println("Could not load " + fontURL + + " (" + e.getLocalizedMessage() + ")"); + } + + public void fontSubstituted(Object source, + FontTriplet requested, FontTriplet effective) { + //ignore + } + + public void glyphNotAvailable(Object source, char ch, String fontName) { + //ignore + } + + }; + + FontListGenerator listGenerator = new FontListGenerator(); + SortedMap fontFamilies = listGenerator.listFonts(fopFactory, configMime, listener); + + if (this.mode == GENERATE_CONSOLE) { + writeToConsole(fontFamilies); + } else { + writeOutput(fontFamilies); + } + } + + private void writeToConsole(SortedMap fontFamilies) + throws TransformerConfigurationException, SAXException, IOException { + Iterator iter = fontFamilies.entrySet().iterator(); + while (iter.hasNext()) { + Map.Entry entry = (Map.Entry)iter.next(); + String firstFamilyName = (String)entry.getKey(); + System.out.println(firstFamilyName + ":"); + List list = (List)entry.getValue(); + Iterator fonts = list.iterator(); + while (fonts.hasNext()) { + FontSpec f = (FontSpec)fonts.next(); + System.out.println(" " + f.getKey() + " " + f.getFamilyNames()); + Iterator triplets = f.getTriplets().iterator(); + while (triplets.hasNext()) { + FontTriplet triplet = (FontTriplet)triplets.next(); + System.out.println(" " + triplet.toString()); + } + } + } + } + + private void writeOutput(SortedMap fontFamilies) + throws TransformerConfigurationException, SAXException, IOException { + if (this.outputFile.isDirectory()) { + System.out.println("Creating one file for each family..."); + Iterator iter = fontFamilies.entrySet().iterator(); + while (iter.hasNext()) { + Map.Entry entry = (Map.Entry)iter.next(); + String familyName = (String)entry.getKey(); + System.out.println("Creating output file for " + familyName + "..."); + String filename; + switch(this.mode) { + case GENERATE_RENDERED: + filename = familyName + ".pdf"; + break; + case GENERATE_FO: + filename = familyName + ".fo"; + break; + case GENERATE_XML: + filename = familyName + ".xml"; + break; + default: + throw new IllegalStateException("Unsupported mode"); + } + File outFile = new File(this.outputFile, filename); + generateXML(fontFamilies, outFile, familyName); + } + } else { + System.out.println("Creating output file..."); + generateXML(fontFamilies, this.outputFile, this.singleFamilyFilter); + } + System.out.println(this.outputFile + " written."); + } + + private static void printVersion() { + System.out.println("Apache FOP " + Version.getVersion() + + " - http://xmlgraphics.apache.org/fop/\n"); + } + + private static void printHelp() { + printVersion(); + + String className = FontListMain.class.getName(); + PrintStream out = System.out; + out.println("USAGE"); + out.println(" java [vmargs] " + className + + " [-c ] [-f ] [[output-dir|output-file] [font-family]]"); + out.println(); + out.println("PARAMETERS"); + out.println(" config-file: an optional FOP configuration file"); + out.println(" mime: The MIME type of the output format for which to"); + out.println(" create the font list (defaults to application/pdf)"); + out.println(" output-dir: Creates one sample PDF per font-family"); + out.println(" output-file: writes the list as file (valid file extensions: xml, fo, pdf)"); + out.println(" font-family: filters to a single font family"); + out.println(); + out.println("EXAMPLE"); + out.println(" java [vmargs] " + className + + " -c userconfig.xml all-fonts.pdf"); + out.println(" --> this generates a single PDF containing a sample"); + out.println(" of all configured fonts."); + out.println(" java [vmargs] " + className + + " -c userconfig.xml"); + out.println(" --> this prints all configured fonts to the console."); + out.println(); + } + + private void parseArguments(String[] args) { + if (args.length > 0) { + int idx = 0; + if ("--help".equals(args[idx]) || "-?".equals(args[idx]) || "-h".equals(args[idx])) { + printHelp(); + System.exit(0); + } + if (idx < args.length - 1 && "-c".equals(args[idx])) { + String filename = args[idx + 1]; + this.configFile = new File(filename); + idx += 2; + } + if (idx < args.length - 1 && "-f".equals(args[idx])) { + this.configMime = args[idx + 1]; + idx += 2; + } + if (idx < args.length) { + String name = args[idx]; + this.outputFile = new File(name); + if (this.outputFile.isDirectory()) { + this.mode = GENERATE_RENDERED; + this.outputMime = MimeConstants.MIME_PDF; + } else if (FilenameUtils.getExtension(name).equalsIgnoreCase("pdf")) { + this.mode = GENERATE_RENDERED; + this.outputMime = MimeConstants.MIME_PDF; + } else if (FilenameUtils.getExtension(name).equalsIgnoreCase("fo")) { + this.mode = GENERATE_FO; + } else if (FilenameUtils.getExtension(name).equalsIgnoreCase("xml")) { + this.mode = GENERATE_XML; + } else { + throw new IllegalArgumentException( + "Operating mode for the output file cannot be determined" + + " or is unsupported: " + name); + } + idx++; + } + if (idx < args.length) { + this.singleFamilyFilter = args[idx]; + } + } else { + System.out.println("use --help or -? for usage information."); + } + } + + /** + * The command-line interface. + * @param args the command-line arguments + */ + public static void main(String[] args) { + try { + FontListMain app = new FontListMain(); + app.parseArguments(args); + app.generate(); + } catch (Throwable t) { + printHelp(); + t.printStackTrace(); + System.exit(-1); + } + } + +} diff --git a/src/java/org/apache/fop/tools/fontlist/FontListSerializer.java b/src/java/org/apache/fop/tools/fontlist/FontListSerializer.java new file mode 100644 index 000000000..eab3caa56 --- /dev/null +++ b/src/java/org/apache/fop/tools/fontlist/FontListSerializer.java @@ -0,0 +1,142 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* $Id$ */ + +package org.apache.fop.tools.fontlist; + +import java.util.Collection; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.SortedMap; +import java.util.regex.Pattern; + +import org.xml.sax.SAXException; +import org.xml.sax.helpers.AttributesImpl; + +import org.apache.fop.fonts.FontTriplet; +import org.apache.fop.util.GenerationHelperContentHandler; + +/** + * Turns the font list into SAX events. + */ +public class FontListSerializer { + + private static final String FONTS = "fonts"; + private static final String FAMILY = "family"; + private static final String FONT = "font"; + private static final String TRIPLETS = "triplets"; + private static final String TRIPLET = "triplet"; + + private static final String NAME = "name"; + private static final String STRIPPED_NAME = "stripped-name"; + private static final String TYPE = "type"; + private static final String KEY = "key"; + private static final String STYLE = "style"; + private static final String WEIGHT = "weight"; + + private static final String CDATA = "CDATA"; + + /** + * Generates SAX events from the font damily map. + * @param fontFamilies the font families + * @param handler the target SAX handler + * @throws SAXException if an XML-related exception occurs + */ + public void generateSAX(SortedMap fontFamilies, + GenerationHelperContentHandler handler) throws SAXException { + generateSAX(fontFamilies, null, handler); + } + + /** + * Generates SAX events from the font damily map. + * @param fontFamilies the font families + * @param singleFamily if not null, the output will be filtered so only this single font family + * will be used + * @param handler the target SAX handler + * @throws SAXException if an XML-related exception occurs + */ + public void generateSAX(SortedMap fontFamilies, String singleFamily, + GenerationHelperContentHandler handler) throws SAXException { + handler.startDocument(); + AttributesImpl atts = new AttributesImpl(); + handler.startElement(FONTS, atts); + + Iterator iter = fontFamilies.entrySet().iterator(); + while (iter.hasNext()) { + Map.Entry entry = (Map.Entry)iter.next(); + String familyName = (String)entry.getKey(); + if (singleFamily != null && familyName != singleFamily) { + continue; + } + atts.clear(); + atts.addAttribute(null, NAME, NAME, CDATA, familyName); + atts.addAttribute(null, STRIPPED_NAME, STRIPPED_NAME, CDATA, + stripQuotes(familyName)); + handler.startElement(FAMILY, atts); + + List containers = (List)entry.getValue(); + generateXMLForFontContainers(handler, containers); + handler.endElement(FAMILY); + } + + handler.endElement(FONTS); + handler.endDocument(); + } + + private final Pattern quotePattern = Pattern.compile("'"); + + private String stripQuotes(String name) { + return quotePattern.matcher(name).replaceAll(""); + } + + private void generateXMLForFontContainers(GenerationHelperContentHandler handler, + List containers) throws SAXException { + AttributesImpl atts = new AttributesImpl(); + Iterator fontIter = containers.iterator(); + while (fontIter.hasNext()) { + FontSpec cont = (FontSpec)fontIter.next(); + atts.clear(); + atts.addAttribute(null, KEY, KEY, CDATA, cont.getKey()); + atts.addAttribute(null, TYPE, TYPE, CDATA, + cont.getFontMetrics().getFontType().getName()); + handler.startElement(FONT, atts); + generateXMLForTriplets(handler, cont.getTriplets()); + handler.endElement(FONT); + } + } + + private void generateXMLForTriplets(GenerationHelperContentHandler handler, Collection triplets) + throws SAXException { + AttributesImpl atts = new AttributesImpl(); + atts.clear(); + handler.startElement(TRIPLETS, atts); + Iterator iter = triplets.iterator(); + while (iter.hasNext()) { + FontTriplet triplet = (FontTriplet)iter.next(); + atts.clear(); + atts.addAttribute(null, NAME, NAME, CDATA, triplet.getName()); + atts.addAttribute(null, STYLE, STYLE, CDATA, triplet.getStyle()); + atts.addAttribute(null, WEIGHT, WEIGHT, CDATA, + Integer.toString(triplet.getWeight())); + handler.element(TRIPLET, atts); + } + handler.endElement(TRIPLETS); + } + +} diff --git a/src/java/org/apache/fop/tools/fontlist/FontSpec.java b/src/java/org/apache/fop/tools/fontlist/FontSpec.java new file mode 100644 index 000000000..ce5c7a6c7 --- /dev/null +++ b/src/java/org/apache/fop/tools/fontlist/FontSpec.java @@ -0,0 +1,103 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* $Id$ */ + +package org.apache.fop.tools.fontlist; + +import java.util.Collection; +import java.util.Collections; +import java.util.SortedSet; + +import org.apache.fop.fonts.FontMetrics; +import org.apache.fop.fonts.FontTriplet; + +/** + * Represents a font with information on how it can be used from XSL-FO. + */ +public class FontSpec implements Comparable { + + private String key; + private FontMetrics metrics; + private SortedSet familyNames = new java.util.TreeSet(); + private Collection triplets = new java.util.TreeSet(); + + /** + * Creates a new font spec. + * @param key the internal font key + * @param metrics the font metrics + */ + public FontSpec(String key, FontMetrics metrics) { + this.key = key; + this.metrics = metrics; + } + + /** + * Adds font family names. + * @param names the names + */ + public void addFamilyNames(Collection names) { + this.familyNames.addAll(names); + } + + /** + * Adds a font triplet. + * @param triplet the font triplet + */ + public void addTriplet(FontTriplet triplet) { + this.triplets.add(triplet); + } + + /** + * Returns the font family names. + * @return the font family names + */ + public SortedSet getFamilyNames() { + return Collections.unmodifiableSortedSet(this.familyNames); + } + + /** + * Returns the font triplets. + * @return the font triplets + */ + public Collection getTriplets() { + return Collections.unmodifiableCollection(this.triplets); + } + + /** + * Returns the internal font key. + * @return the internal font key + */ + public String getKey() { + return this.key; + } + + /** + * Returns the font metrics. + * @return the font metrics + */ + public FontMetrics getFontMetrics() { + return this.metrics; + } + + /** {@inheritDoc} */ + public int compareTo(Object o) { + FontSpec other = (FontSpec)o; + return metrics.getFullName().compareTo(other.metrics.getFullName()); + } + +} \ No newline at end of file diff --git a/src/java/org/apache/fop/tools/fontlist/fonts2fo.xsl b/src/java/org/apache/fop/tools/fontlist/fonts2fo.xsl new file mode 100644 index 000000000..5c2b59e8e --- /dev/null +++ b/src/java/org/apache/fop/tools/fontlist/fonts2fo.xsl @@ -0,0 +1,200 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Table of Contents + + + + + + + + + + FOP Font List + The number of font families: + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Fonts: + + + + + + + + + + + + + + + Weight Sample: font-family="" font-weight="100..900" + + + + + 100: The quick brown fox jumps over the lazy dog + 200: The quick brown fox jumps over the lazy dog + 300: The quick brown fox jumps over the lazy dog + 400: The quick brown fox jumps over the lazy dog + 500: The quick brown fox jumps over the lazy dog + 600: The quick brown fox jumps over the lazy dog + 700: The quick brown fox jumps over the lazy dog + 800: The quick brown fox jumps over the lazy dog + 900: The quick brown fox jumps over the lazy dog + + + + + SVG + + + + '' + + + 100: The quick brown fox jumps over the lazy dog + 200: The quick brown fox jumps over the lazy dog + 300: The quick brown fox jumps over the lazy dog + 400: The quick brown fox jumps over the lazy dog + 500: The quick brown fox jumps over the lazy dog + 600: The quick brown fox jumps over the lazy dog + 700: The quick brown fox jumps over the lazy dog + 800: The quick brown fox jumps over the lazy dog + 900: The quick brown fox jumps over the lazy dog + + + + + + + + + + + Internal key: + + + Sample: + + The quick brown fox jumps over the lazy dog. + + + + Accessible by: + + + + + + + + + font-family="" + font-style=" + font-weight=" + + + -- cgit v1.2.3