Index: test/java/org/apache/fop/StandardTestSuite.java
===================================================================
--- test/java/org/apache/fop/StandardTestSuite.java	(revision 908040)
+++ test/java/org/apache/fop/StandardTestSuite.java	(working copy)
@@ -22,6 +22,7 @@
 import junit.framework.Test;
 import junit.framework.TestSuite;
 
+import org.apache.fop.afp.AFPTestSuite;
 import org.apache.fop.fonts.DejaVuLGCSerifTest;
 import org.apache.fop.fonts.TrueTypeAnsiTestCase;
 import org.apache.fop.image.loader.batik.ImageLoaderTestCase;
@@ -49,6 +50,7 @@
         TestSuite suite = new TestSuite("Basic functionality test suite for FOP");
         //$JUnit-BEGIN$
         suite.addTest(BasicDriverTestSuite.suite());
+        suite.addTest(AFPTestSuite.suite());
         suite.addTest(UtilityCodeTestSuite.suite());
         suite.addTest(new TestSuite(PDFAConformanceTestCase.class));
         suite.addTest(new TestSuite(PDFEncodingTestCase.class));
Index: conf/fop.xconf
===================================================================
--- conf/fop.xconf	(revision 908040)
+++ conf/fop.xconf	(working copy)
@@ -397,14 +397,29 @@
           <font-triplet name="monospace" style="italic" weight="bold"/>
         </font>
         
+        
+        
+	      <!--  Configuring a fallback strategy for CID Keyed fonts.
+	      
+	      This example is a redundant copy of the default fallback strategy.
+	       
+	       <fallback-strategy name="default strategy" >
+	            <block name = "CJK_COMPATIBILITY_IDEOGRAPHS" />
+	            <block name = "CJK_UNIFIED_IDEOGRAPHS" />
+	            <block name = "CJK_UNIFIED_IDEOGRAPHS_EXTENSION_A" />
+	       </fallback-strategy>
+	       
+	       See  the FOP documentation for more configuration options.
+	       -->
+        
          <!-- 
-        Configure double-byte (CID Keyed font (Type 0)) AFP fonts with type="CIDKeyed".  
-        
-        example:
+        Configuring a double-byte (CID Keyed font (Type 0)) AFP font.   
+
          <font>
         	<afp-font type="CIDKeyed" encoding="UnicodeBigUnmarked"  
         	codepage="T1120000" characterset="CZJHMNU" 
-        	base-uri="fonts" />
+        	base-uri="fonts">
+        	<fallback-strategy ref="default strategy"/>
          	<font-triplet name="J-Heisei Mincho" style="normal" weight="normal" />
      	 </font>
         -->
Index: src/java/org/apache/fop/render/afp/AFPRendererConfigurator.java
===================================================================
--- src/java/org/apache/fop/render/afp/AFPRendererConfigurator.java	(revision 908040)
+++ src/java/org/apache/fop/render/afp/AFPRendererConfigurator.java	(working copy)
@@ -33,9 +33,10 @@
 import org.apache.fop.afp.fonts.AFPFont;
 import org.apache.fop.afp.fonts.AFPFontCollection;
 import org.apache.fop.afp.fonts.AFPFontInfo;
+import org.apache.fop.afp.fonts.CIDKeyedFont;
 import org.apache.fop.afp.fonts.CharacterSet;
 import org.apache.fop.afp.fonts.CharacterSetBuilder;
-import org.apache.fop.afp.fonts.DoubleByteFont;
+import org.apache.fop.afp.fonts.FallbackStrategyFactory;
 import org.apache.fop.afp.fonts.OutlineFont;
 import org.apache.fop.afp.fonts.RasterFont;
 import org.apache.fop.afp.util.DefaultFOPResourceAccessor;
@@ -58,13 +59,14 @@
 /**
  * AFP Renderer configurator
  */
-public class AFPRendererConfigurator extends PrintRendererConfigurator
-        implements IFDocumentHandlerConfigurator {
+public class AFPRendererConfigurator extends PrintRendererConfigurator implements
+IFDocumentHandlerConfigurator {
 
     /**
      * Default constructor
      *
-     * @param userAgent user agent
+     * @param userAgent
+     *            user agent
      */
     public AFPRendererConfigurator(FOUserAgent userAgent) {
         super(userAgent);
@@ -76,7 +78,10 @@
         FontManager fontManager = this.userAgent.getFactory().getFontManager();
 
         Configuration[] triple = fontCfg.getChildren("font-triplet");
-        List/*<FontTriplet>*/ tripletList = new java.util.ArrayList/*<FontTriplet>*/();
+        List/* <FontTriplet> */tripletList = new java.util.ArrayList/*
+         * <FontTriplet
+         * >
+         */();
         if (triple.length == 0) {
             log.error("Mandatory font configuration element '<font-triplet...' is missing");
             return null;
@@ -84,12 +89,11 @@
         for (int j = 0; j < triple.length; j++) {
             int weight = FontUtil.parseCSS2FontWeight(triple[j].getAttribute("weight"));
             FontTriplet triplet = new FontTriplet(triple[j].getAttribute("name"),
-                    triple[j].getAttribute("style"),
-                    weight);
+                    triple[j].getAttribute("style"), weight);
             tripletList.add(triplet);
         }
 
-        //build the fonts
+        // build the fonts
         Configuration afpFontCfg = fontCfg.getChild("afp-font");
         if (afpFontCfg == null) {
             log.error("Mandatory font configuration element '<afp-font...' is missing");
@@ -99,7 +103,7 @@
         URI baseURI = null;
         String uri = afpFontCfg.getAttribute("base-uri", fontPath);
         if (uri == null) {
-            //Fallback for old attribute which only supports local filenames
+            // Fallback for old attribute which only supports local filenames
             String path = afpFontCfg.getAttribute("path", fontPath);
             if (path != null) {
                 File f = new File(path);
@@ -113,10 +117,8 @@
                 return null;
             }
         }
-        ResourceAccessor accessor = new DefaultFOPResourceAccessor(
-                this.userAgent,
-                fontManager.getFontBaseURL(),
-                baseURI);
+        ResourceAccessor accessor = new DefaultFOPResourceAccessor(this.userAgent, fontManager
+                .getFontBaseURL(), baseURI);
 
         String type = afpFontCfg.getAttribute("type");
         if (type == null) {
@@ -140,21 +142,22 @@
         return font != null ? new AFPFontInfo(font, tripletList) : null;
     }
 
-
     /**
      * Create the AFPFont based on type and type-dependent configuration.
      *
-     * @param type font type e.g. 'raster', 'outline'
-     * @param codepage codepage file
-     * @param encoding character encoding e.g. 'Cp500', 'UnicodeBigUnmarked'
+     * @param type
+     *            font type e.g. 'raster', 'outline'
+     * @param codepage
+     *            codepage file
+     * @param encoding
+     *            character encoding e.g. 'Cp500', 'UnicodeBigUnmarked'
      * @param accessor
      * @param afpFontCfg
      * @return
      * @throws ConfigurationException
      */
     private AFPFont fontFromType(String type, String codepage, String encoding,
-            ResourceAccessor accessor, Configuration afpFontCfg)
-    throws ConfigurationException {
+            ResourceAccessor accessor, Configuration afpFontCfg) throws ConfigurationException {
 
         if ("raster".equalsIgnoreCase(type)) {
 
@@ -174,23 +177,21 @@
 
                 String characterset = rasterCfg.getAttribute("characterset");
                 if (characterset == null) {
-                    log.error(
-                    "Mandatory afp-raster-font configuration attribute 'characterset=' is missing");
+                    log.error("Mandatory afp-raster-font configuration attribute 'characterset'"
+                            + "is missing");
                     return null;
                 }
                 float size = rasterCfg.getAttributeAsFloat("size");
-                int sizeMpt = (int)(size * 1000);
+                int sizeMpt = (int) (size * 1000);
                 String base14 = rasterCfg.getAttribute("base14-font", null);
 
                 if (base14 != null) {
                     try {
-                        Class clazz = Class.forName("org.apache.fop.fonts.base14."
-                                + base14);
+                        Class clazz = Class.forName("org.apache.fop.fonts.base14." + base14);
                         try {
-                            Typeface tf = (Typeface)clazz.newInstance();
-                            font.addCharacterSet(sizeMpt,
-                                    CharacterSetBuilder.getInstance()
-                                        .build(characterset, codepage, encoding, tf));
+                            Typeface tf = (Typeface) clazz.newInstance();
+                            font.addCharacterSet(sizeMpt, CharacterSetBuilder.getInstance().build(
+                                    characterset, codepage, encoding, tf));
                         } catch (Exception ie) {
                             String msg = "The base 14 font class " + clazz.getName()
                             + " could not be instantiated";
@@ -202,8 +203,8 @@
                         log.error(msg);
                     }
                 } else {
-                    font.addCharacterSet(sizeMpt, CharacterSetBuilder.getInstance()
-                            .build(characterset, codepage, encoding, accessor));
+                    font.addCharacterSet(sizeMpt, CharacterSetBuilder.getInstance().build(
+                            characterset, codepage, encoding, accessor));
                 }
             }
             return font;
@@ -219,12 +220,11 @@
             String base14 = afpFontCfg.getAttribute("base14-font", null);
             if (base14 != null) {
                 try {
-                    Class clazz = Class.forName("org.apache.fop.fonts.base14."
-                            + base14);
+                    Class clazz = Class.forName("org.apache.fop.fonts.base14." + base14);
                     try {
-                        Typeface tf = (Typeface)clazz.newInstance();
-                        characterSet = CharacterSetBuilder.getInstance()
-                                        .build(characterset, codepage, encoding, tf);
+                        Typeface tf = (Typeface) clazz.newInstance();
+                        characterSet = CharacterSetBuilder.getInstance().build(characterset,
+                                codepage, encoding, tf);
                     } catch (Exception ie) {
                         String msg = "The base 14 font class " + clazz.getName()
                         + " could not be instantiated";
@@ -236,8 +236,8 @@
                     log.error(msg);
                 }
             } else {
-                characterSet = CharacterSetBuilder.getInstance().build(
-                        characterset, codepage, encoding, accessor);
+                characterSet = CharacterSetBuilder.getInstance().build(characterset, codepage,
+                        encoding, accessor);
             }
             // Return new font object
             return new OutlineFont(name, characterSet);
@@ -250,13 +250,22 @@
             }
             String name = afpFontCfg.getAttribute("name", characterset);
             CharacterSet characterSet = null;
-            characterSet = CharacterSetBuilder.getDoubleByteInstance()
-                            .build(characterset, codepage, encoding, accessor);
+            characterSet = CharacterSetBuilder.getDoubleByteInstance().build(characterset,
+                    codepage, encoding, accessor);
 
-            // Create a new font object
-            DoubleByteFont font = new DoubleByteFont(name, characterSet);
-            return font;
+            Configuration fallbackStrategy = afpFontCfg.getChild("fallback-strategy", false);
 
+            // has a fallback strategy been configured?
+            if (fallbackStrategy != null) {
+                try {
+                    return createCIDKeyedWithFallbackStrategy(name, characterSet, fallbackStrategy);
+                } catch (Exception e) {
+                    throw new ConfigurationException(
+                            "Unable to configure fallback strategy for font " + name, e);
+                }
+            }
+            return new CIDKeyedFont(name, characterSet);
+
         } else {
             log.error("No or incorrect type attribute: " + type);
         }
@@ -267,11 +276,13 @@
     /**
      * Builds a list of AFPFontInfo objects for use with the setup() method.
      *
-     * @param cfg Configuration object
+     * @param cfg
+     *            Configuration object
      * @return List the newly created list of fonts
-     * @throws ConfigurationException if something's wrong with the config data
+     * @throws ConfigurationException
+     *             if something's wrong with the config data
      */
-    private List/*<AFPFontInfo>*/ buildFontListFromConfiguration(Configuration cfg)
+    private List/* <AFPFontInfo> */buildFontListFromConfiguration(Configuration cfg)
     throws FOPException, ConfigurationException {
 
         Configuration fonts = cfg.getChild("fonts");
@@ -285,11 +296,15 @@
         // Renderer-specific referenced fonts
         Configuration referencedFontsCfg = fonts.getChild("referenced-fonts", false);
         if (referencedFontsCfg != null) {
-            localMatcher = FontManagerConfigurator.createFontsMatcher(
-                    referencedFontsCfg, this.userAgent.getFactory().validateUserConfigStrictly());
+            localMatcher = FontManagerConfigurator.createFontsMatcher(referencedFontsCfg,
+                    this.userAgent.getFactory().validateUserConfigStrictly());
         }
 
-        List/*<AFPFontInfo>*/ fontList = new java.util.ArrayList();
+        //  Fallback Strategy
+        configureFallbackStrategies(fonts.getChildren("fallback-strategy"));
+
+
+        List/* <AFPFontInfo> */fontList = new java.util.ArrayList();
         Configuration[] font = fonts.getChildren("font");
         final String fontPath = null;
         for (int i = 0; i < font.length; i++) {
@@ -298,14 +313,12 @@
                 if (log.isDebugEnabled()) {
                     log.debug("Adding font " + afi.getAFPFont().getFontName());
                 }
-                List/*<FontTriplet>*/ fontTriplets = afi.getFontTriplets();
+                List/* <FontTriplet> */fontTriplets = afi.getFontTriplets();
                 for (int j = 0; j < fontTriplets.size(); ++j) {
                     FontTriplet triplet = (FontTriplet) fontTriplets.get(j);
                     if (log.isDebugEnabled()) {
-                        log.debug("  Font triplet "
-                                + triplet.getName() + ", "
-                                + triplet.getStyle() + ", "
-                                + triplet.getWeight());
+                        log.debug("  Font triplet " + triplet.getName() + ", " + triplet.getStyle()
+                                + ", " + triplet.getWeight());
                     }
 
                     if ((referencedFontsMatcher != null && referencedFontsMatcher.matches(triplet))
@@ -321,6 +334,53 @@
         return fontList;
     }
 
+    private CIDKeyedFont createCIDKeyedWithFallbackStrategy(String name, CharacterSet characterSet,
+            Configuration fallbackStrategy) throws Exception {
+
+
+        String ref = fallbackStrategy.getAttribute("ref", null);
+
+        if(ref != null){
+            return new CIDKeyedFont(name, characterSet,
+                    FallbackStrategyFactory.instance()
+                    .getRegisteredStrategy(ref));
+        }
+
+
+        try {
+            String url = fallbackStrategy.getAttribute("url");
+
+            return new CIDKeyedFont(name, characterSet,
+                    FallbackStrategyFactory.instance()
+                    .registerStrategy(new File(url)));
+
+        } catch (Exception e) {
+            //optional attribute
+        }
+
+        return new CIDKeyedFont(name, characterSet,
+                FallbackStrategyFactory.instance().newStrategy(fallbackStrategy));
+    }
+
+    private void configureFallbackStrategies( Configuration[] fallbackStrategyCfgArray)
+    throws ConfigurationException {
+        for (int i = 0; i < fallbackStrategyCfgArray.length; i++) {
+
+            Configuration fallbackStrategyCfg = fallbackStrategyCfgArray[i];
+            String name = fallbackStrategyCfg.getAttribute("name");
+
+
+            try {
+                FallbackStrategyFactory.instance().registerStrategy(name, fallbackStrategyCfg);
+            } catch (Exception e) {
+                //poor configuration
+                throw new ConfigurationException("Badly formed fallback strategy:\n" + e.getMessage());
+            }
+        }
+    }
+
+
+
     /** images are converted to grayscale bitmapped IOCA */
     private static final String IMAGES_MODE_GRAYSCALE = "b+w";
 
@@ -330,21 +390,24 @@
     /**
      * Configure the AFP renderer.
      *
-     * @param renderer AFP renderer
-     * @throws FOPException fop exception
+     * @param renderer
+     *            AFP renderer
+     * @throws FOPException
+     *             fop exception
      * @see org.apache.fop.render.PrintRendererConfigurator#configure(Renderer)
      */
     public void configure(Renderer renderer) throws FOPException {
         Configuration cfg = super.getRendererConfig(renderer);
         if (cfg != null) {
-            AFPRenderer afpRenderer = (AFPRenderer)renderer;
+            AFPRenderer afpRenderer = (AFPRenderer) renderer;
 
             try {
-                List/*<AFPFontInfo>*/ fontList = buildFontListFromConfiguration(cfg);
+                List/* <AFPFontInfo> */fontList = buildFontListFromConfiguration(cfg);
                 afpRenderer.setFontList(fontList);
             } catch (ConfigurationException e) {
-                LogUtil.handleException(log, e,
-                        userAgent.getFactory().validateUserConfigStrictly());
+                LogUtil
+                .handleException(log, e, userAgent.getFactory()
+                        .validateUserConfigStrictly());
             }
 
             configure(afpRenderer, cfg);
@@ -376,8 +439,8 @@
 
         // shading (filled rectangles)
         Configuration shadingCfg = cfg.getChild("shading");
-        AFPShadingMode shadingMode = AFPShadingMode.valueOf(
-                shadingCfg.getValue(AFPShadingMode.COLOR.getName()));
+        AFPShadingMode shadingMode = AFPShadingMode.valueOf(shadingCfg
+                .getValue(AFPShadingMode.COLOR.getName()));
         customizable.setShadingMode(shadingMode);
 
         // renderer resolution
@@ -387,8 +450,7 @@
         }
 
         // a default external resource group file setting
-        Configuration resourceGroupFileCfg
-        = cfg.getChild("resource-group-file", false);
+        Configuration resourceGroupFileCfg = cfg.getChild("resource-group-file", false);
         if (resourceGroupFileCfg != null) {
             String resourceGroupDest = null;
             try {
@@ -404,11 +466,12 @@
                     }
                 }
             } catch (ConfigurationException e) {
-                LogUtil.handleException(log, e,
-                        userAgent.getFactory().validateUserConfigStrictly());
+                LogUtil
+                .handleException(log, e, userAgent.getFactory()
+                        .validateUserConfigStrictly());
             } catch (IOException ioe) {
                 throw new FOPException("Could not create default external resource group file"
-                            , ioe);
+                        , ioe);
             }
         }
 
@@ -422,11 +485,11 @@
                     String level = defaultResourceLevelCfg.getAttribute(type);
                     defaults.setDefaultResourceLevel(type, AFPResourceLevel.valueOf(level));
                 } catch (IllegalArgumentException iae) {
-                    LogUtil.handleException(log, iae,
-                            userAgent.getFactory().validateUserConfigStrictly());
+                    LogUtil.handleException(log, iae, userAgent.getFactory()
+                            .validateUserConfigStrictly());
                 } catch (ConfigurationException e) {
-                    LogUtil.handleException(log, e,
-                            userAgent.getFactory().validateUserConfigStrictly());
+                    LogUtil.handleException(log, e, userAgent.getFactory()
+                            .validateUserConfigStrictly());
                 }
             }
             customizable.setResourceLevelDefaults(defaults);
@@ -437,14 +500,14 @@
     public void configure(IFDocumentHandler documentHandler) throws FOPException {
         Configuration cfg = super.getRendererConfig(documentHandler.getMimeType());
         if (cfg != null) {
-            AFPDocumentHandler afpDocumentHandler = (AFPDocumentHandler)documentHandler;
+            AFPDocumentHandler afpDocumentHandler = (AFPDocumentHandler) documentHandler;
             configure(afpDocumentHandler, cfg);
         }
     }
 
     /** {@inheritDoc} */
     public void setupFontInfo(IFDocumentHandler documentHandler, FontInfo fontInfo)
-            throws FOPException {
+    throws FOPException {
         FontManager fontManager = userAgent.getFactory().getFontManager();
         List fontCollections = new java.util.ArrayList();
 
@@ -452,19 +515,19 @@
         if (cfg != null) {
             try {
                 List fontList = buildFontListFromConfiguration(cfg);
-                fontCollections.add(new AFPFontCollection(
-                        userAgent.getEventBroadcaster(), fontList));
+                fontCollections
+                .add(new AFPFontCollection(userAgent.getEventBroadcaster(), fontList));
             } catch (ConfigurationException e) {
-                LogUtil.handleException(log, e,
-                        userAgent.getFactory().validateUserConfigStrictly());
+                LogUtil
+                .handleException(log, e, userAgent.getFactory()
+                        .validateUserConfigStrictly());
             }
         } else {
             fontCollections.add(new AFPFontCollection(userAgent.getEventBroadcaster(), null));
         }
 
-        fontManager.setup(fontInfo,
-                (FontCollection[])fontCollections.toArray(
-                        new FontCollection[fontCollections.size()]));
+        fontManager.setup(fontInfo, (FontCollection[]) fontCollections
+                .toArray(new FontCollection[fontCollections.size()]));
         documentHandler.setFontInfo(fontInfo);
     }
 }
Index: src/java/org/apache/fop/afp/modca/MapCodedFont.java
===================================================================
--- src/java/org/apache/fop/afp/modca/MapCodedFont.java	(revision 908040)
+++ src/java/org/apache/fop/afp/modca/MapCodedFont.java	(working copy)
@@ -29,7 +29,7 @@
 import org.apache.fop.afp.AFPConstants;
 import org.apache.fop.afp.fonts.AFPFont;
 import org.apache.fop.afp.fonts.CharacterSet;
-import org.apache.fop.afp.fonts.DoubleByteFont;
+import org.apache.fop.afp.fonts.CIDKeyedFont;
 import org.apache.fop.afp.fonts.FontRuntimeException;
 import org.apache.fop.afp.fonts.OutlineFont;
 import org.apache.fop.afp.fonts.RasterFont;
@@ -221,8 +221,8 @@
                         AFPConstants.EBCIDIC_ENCODING)
                         + " must have a fixed length of 8 characters.");
                 }
-            }  else if (font instanceof DoubleByteFont) {
-                DoubleByteFont outline = (DoubleByteFont) font;
+            }  else if (font instanceof CIDKeyedFont) {
+                CIDKeyedFont outline = (CIDKeyedFont) font;
                 CharacterSet cs = outline.getCharacterSet();
                 fontDefinition.characterSet = cs.getNameBytes();
 
Index: src/java/org/apache/fop/afp/fonts/IMetricFallbackStrategy.java
===================================================================
--- src/java/org/apache/fop/afp/fonts/IMetricFallbackStrategy.java	(revision 0)
+++ src/java/org/apache/fop/afp/fonts/IMetricFallbackStrategy.java	(revision 0)
@@ -0,0 +1,38 @@
+/*
+ * 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.afp.fonts;
+/**
+ * Encapsulates a fallback strategy for providing substitute metrics for characters
+ * that have no specified font metrics in the font resource.
+ * Intended to be used by the CIDKeyed font.
+ *
+ */
+public interface IMetricFallbackStrategy {
+
+    /**
+     * A strategy for determining.
+     *
+     * @param character the character requiring fallback metric
+     * @param characterSet required for substitute fallback metrics
+     * @return normalised fallback width
+     */
+    int getWidth(int character, CharacterSet characterSet);
+
+}

Property changes on: src/java/org/apache/fop/afp/fonts/IMetricFallbackStrategy.java
___________________________________________________________________
Added: svn:eol-style
   + native

Index: src/java/org/apache/fop/afp/fonts/CIDKeyedFont.java
===================================================================
--- src/java/org/apache/fop/afp/fonts/CIDKeyedFont.java	(revision 903603)
+++ src/java/org/apache/fop/afp/fonts/CIDKeyedFont.java	(working copy)
@@ -19,7 +19,6 @@
 
 package org.apache.fop.afp.fonts;
 
-import java.util.Set;
 
 /**
  * Implementation of AbstractOutlineFont that supports double-byte fonts (CID Keyed font (Type 0)).
@@ -27,28 +26,32 @@
  * a fallback width.  The default width is 1 em.  A character can be supplied and queried for the
  *  fallback width of all non-ideograph characters.<p />
  */
-public class DoubleByteFont extends AbstractOutlineFont {
+public class CIDKeyedFont extends AbstractOutlineFont {
 
     //private static final Log LOG = LogFactory.getLog(DoubleByteFont.class);
 
-    //See also http://unicode.org/reports/tr11/ which we've not closely looked at, yet
-    //TODO the Unicode block listed here is probably not complete (ex. Hiragana, Katakana etc.)
-    private static final Set IDEOGRAPHIC = new java.util.HashSet();
-    static {
-        IDEOGRAPHIC.add(Character.UnicodeBlock.CJK_COMPATIBILITY_IDEOGRAPHS);
-        //IDEOGRAPHIC.add(Character.UnicodeBlock.CJK_COMPATIBILITY_IDEOGRAPHS_SUPPLEMENT); //Java 1.5
-        IDEOGRAPHIC.add(Character.UnicodeBlock.CJK_UNIFIED_IDEOGRAPHS);
-        IDEOGRAPHIC.add(Character.UnicodeBlock.CJK_UNIFIED_IDEOGRAPHS_EXTENSION_A);
-        //IDEOGRAPHIC.add(Character.UnicodeBlock.CJK_UNIFIED_IDEOGRAPHS_EXTENSION_B); //Java 1.1
+    private IMetricFallbackStrategy strategy;
+
+    /**
+     * Constructor for an double-byte outline font.
+     * @param name the name of the font
+     * @param charSet the character set
+     */
+    public CIDKeyedFont(String name, CharacterSet charSet) {
+        super(name, charSet);
+        this.strategy = FallbackStrategyFactory.instance().getDefaultStrategy();
     }
 
+
     /**
      * Constructor for an double-byte outline font.
      * @param name the name of the font
      * @param charSet the character set
+     * @param strategy the fallback strategy
      */
-    public DoubleByteFont(String name, CharacterSet charSet) {
+    public CIDKeyedFont(String name, CharacterSet charSet, IMetricFallbackStrategy strategy) {
         super(name, charSet);
+        this.strategy = strategy;
     }
 
     /** {@inheritDoc} */
@@ -69,22 +72,7 @@
 
     private int inferCharWidth(int character) {
 
-        //Is this character an ideograph?
-        boolean isIdeographic = false;
-        Character.UnicodeBlock charBlock = Character.UnicodeBlock.of((char)character);
-        if (charBlock == null) {
-            isIdeographic = false;
-        } else if (IDEOGRAPHIC.contains(charBlock)) {
-            isIdeographic = true;
-        } else { //default
-            isIdeographic = false;
-        }
-
-        if (isIdeographic) {
-            return charSet.getEmSpaceIncrement();
-        } else {
-            return charSet.getSpaceIncrement();
-        }
+        return strategy.getWidth(character, charSet);
     }
 
 }
Index: src/java/org/apache/fop/afp/fonts/FallbackStrategyFactory.java
===================================================================
--- src/java/org/apache/fop/afp/fonts/FallbackStrategyFactory.java	(revision 0)
+++ src/java/org/apache/fop/afp/fonts/FallbackStrategyFactory.java	(revision 0)
@@ -0,0 +1,274 @@
+/*
+ * 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.afp.fonts;
+
+import java.io.File;
+import java.util.HashMap;
+
+import org.apache.avalon.framework.configuration.Configuration;
+import org.apache.avalon.framework.configuration.ConfigurationException;
+import org.apache.avalon.framework.configuration.DefaultConfigurationBuilder;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+/**
+ * Factory for registering and retrieving instances of
+ *  FontMetricFallbackStrategy
+ *
+ */
+public final  class FallbackStrategyFactory {
+
+    private static FallbackStrategyFactory instance;
+
+    private IMetricFallbackStrategy defaultStrategy;
+
+    private HashMap/*<String, FontMetricFallbackStrategy>*/ registeredStrategies
+    = new HashMap/*<String, FontMetricFallbackStrategy>*/();
+
+
+    private FallbackStrategyFactory() { }
+
+    /**
+     *
+     * @return singleton FallbackStrategyFactory
+     */
+    public static FallbackStrategyFactory instance() {
+
+        if (instance == null) {
+            instance = new FallbackStrategyFactory();
+        }
+        return instance;
+    }
+
+
+    /**
+     *
+     * @return default instance of FontMetricFallbackStrategy
+     */
+    public IMetricFallbackStrategy getDefaultStrategy() {
+        if (defaultStrategy == null) {
+            //  synchronized(instance){
+            defaultStrategy = new DefaultMetricFallbackStrategy();
+            //  }
+        }
+        return defaultStrategy;
+    }
+
+    /**
+     * @param name strategy name
+     * @return FontMetricFallbackStrategy registered with name
+     * @throws Exception if no strategy is registered
+     */
+    public IMetricFallbackStrategy getRegisteredStrategy(String name) throws Exception {
+        String canonicalName = canonicalName(name);
+        if (!registeredStrategies.containsKey(canonicalName)) {
+            throw new Exception("Fallback strategy with name '"
+                    + name + "' has not been registered.");
+        }
+
+        return (IMetricFallbackStrategy)registeredStrategies.get(canonicalName);
+    }
+    /**
+     * Create and register an instance of  FontMetricFallbackStrategy
+     * @param name stategy name
+     * @param fallbackStrategyCfg configuration
+     * @return created and registered instance
+     * @throws Exception if incorrectly parametrized.
+     */
+    public IMetricFallbackStrategy registerStrategy(String name,
+            Configuration fallbackStrategyCfg)
+    throws Exception {
+        String canonicalName = canonicalName(name);
+
+        if (registeredStrategies.containsKey(canonicalName)) {
+            throw new Exception("Fallback strategy registration error:"
+                    + "\n\tAttempted to register  strategy '" +  canonicalName + "' twice.");
+        }
+
+        IMetricFallbackStrategy strategy  = newInstanceFromConfig(fallbackStrategyCfg);
+        registeredStrategies.put(canonicalName, strategy);
+
+        return strategy;
+    }
+
+
+
+    private static MetricFallbackStrategy newInstanceFromConfig(
+            Configuration fallbackStrategyCfg) throws Exception {
+
+        Configuration[] children = fallbackStrategyCfg.getChildren();
+        HashMap/*<String, Double>*/ blockMap = new HashMap/*<String, Double>*/();
+        HashMap/*<Integer, Double>*/ charMap = new HashMap/*<Integer, Double>*/();
+
+        for (int j = 0; j < children.length; j++) {
+            Configuration child  = children[j];
+
+            if (child.getName().equalsIgnoreCase("block")) {
+                Configuration block = child;
+                Double scaleFactor = Double.valueOf(1d);
+                String scaleFactorAttribute = null;
+                try {
+                    scaleFactorAttribute = block.getAttribute("scale-factor");
+                    scaleFactor = Double.valueOf(scaleFactorAttribute);
+                } catch (ConfigurationException ce) {
+                    //Attribute scale-factor is optional
+                } catch (NumberFormatException nfe) {
+                    throw new ConfigurationException( "A block element is badly formed:\n"
+                            + "\t block attribute scale-factor value '"
+                            + scaleFactorAttribute + "' is not a double.");
+                }
+                blockMap.put(block.getAttribute("name"), scaleFactor);
+            } else if (child.getName().equalsIgnoreCase("character")) {
+                Configuration character = child;
+                Double scaleFactor = Double.valueOf(1d);
+                String scaleFactorAttribute = null;
+                try {
+                    scaleFactorAttribute = character.getAttribute("scale-factor");
+                    scaleFactor = Double.valueOf(scaleFactorAttribute);
+                } catch (ConfigurationException ce) {
+                    //Attribute scale-factor is optional
+                } catch (NumberFormatException nfe) {
+                    throw new ConfigurationException(
+                        "A fallback-strategy.block element is badly formed:"
+                            + "\n\tblock attribute scale-factor value '"
+                        + scaleFactorAttribute + "' is not a double.");
+                }
+
+                String codepointAttr = character.getAttribute("char");
+
+                Integer codepoint;
+                if (codepointAttr.isEmpty()) {
+                    throw new ConfigurationException("Empty codepoint attribute");
+                }
+                else if (codepointAttr.matches("[Uu]\\+.*")) {
+                    try {
+                        codepoint = Integer.valueOf(
+                                Integer.parseInt(codepointAttr.substring(2), 16));
+                    } catch (NumberFormatException e) {
+                        throw new ConfigurationException("Badly formed codepoint attribute:"
+                                + "\n\t" + codepointAttr + " not in hexidecimal form u+xxxx");
+                    }
+                } else if (codepointAttr.length() == 1) {
+                    codepoint = Integer.valueOf(codepointAttr.codePointAt(0));
+                } else {
+                    throw new ConfigurationException("Badly formed codepoint attribute '"
+                            + codepointAttr + "'");
+                }
+
+                charMap.put(codepoint, scaleFactor);
+            }
+        }
+
+        return new MetricFallbackStrategy(blockMap, charMap);
+    }
+
+    /**
+     * Create and register an instance of  FontMetricFallbackStrategy
+     * @param fallbackStrategyCfg configuration
+     * @return new instance
+     * @throws Exception if in correctly parametrized.
+     */
+    public IMetricFallbackStrategy newStrategy(Configuration fallbackStrategyCfg)
+    throws Exception {
+        return newInstanceFromConfig(fallbackStrategyCfg);
+    }
+
+
+
+    /**
+     * Create and register an instance of  FontMetricFallbackStrategy
+     * @param strategyFile location of strategy file
+        @return created and registered instance
+     * @throws Exception if in correctly parametrized.
+     */
+    public IMetricFallbackStrategy registerStrategy(File strategyFile) throws Exception {
+
+
+
+        String canonicalPath = strategyFile.getCanonicalPath();
+
+        IMetricFallbackStrategy strategy = (IMetricFallbackStrategy)registeredStrategies
+                                                .get(canonicalPath);
+
+        if (strategy == null) {
+            strategy = new LateLoadMetricFallbackStrategy(strategyFile);
+            registeredStrategies.put(canonicalPath, strategy);
+        }
+        return strategy;
+    }
+
+
+
+
+    private static String canonicalName(String name) {
+        return name.toUpperCase();
+    }
+
+    /**
+     * A configurable font metric fallback strategy.
+     * Instances are parametrised by block and character fallback mappings.
+     *
+     *
+     */
+    private static class LateLoadMetricFallbackStrategy implements IMetricFallbackStrategy {
+
+        private static final Log LOG = LogFactory.getLog(LateLoadMetricFallbackStrategy.class);
+
+        private IMetricFallbackStrategy delegate = null;
+
+        private File configFile;
+
+
+        /**
+         * Constructor.
+         * @param configFile location of configuration file
+         */
+        protected LateLoadMetricFallbackStrategy(File configFile) {
+           this.configFile = configFile;
+        }
+
+
+        /**
+         * {@inheritDoc}
+         */
+
+        public int getWidth(int character, CharacterSet charSet) {
+            return getDelegate().getWidth(character, charSet);
+        }
+
+        private IMetricFallbackStrategy getDelegate() {
+            if (delegate == null) {
+                try {
+
+                    DefaultConfigurationBuilder cfgBuilder = new DefaultConfigurationBuilder();
+                    Configuration fallbackStrategyCfg = cfgBuilder.buildFromFile(configFile);
+
+                    delegate = FallbackStrategyFactory.newInstanceFromConfig(fallbackStrategyCfg);
+                } catch (Exception e) {
+                    LOG.error("Unable to use fallback strategy declared in " + configFile, e);
+                    throw new RuntimeException("Unable to load fallback strategy declared in "
+                            + configFile, e);
+                }
+             }
+             return delegate;
+        }
+    }
+
+
+}

Property changes on: src/java/org/apache/fop/afp/fonts/FallbackStrategyFactory.java
___________________________________________________________________
Added: svn:eol-style
   + native

Index: src/java/org/apache/fop/afp/fonts/CharacterSetOrientation.java
===================================================================
--- src/java/org/apache/fop/afp/fonts/CharacterSetOrientation.java	(revision 908040)
+++ src/java/org/apache/fop/afp/fonts/CharacterSetOrientation.java	(working copy)
@@ -278,7 +278,7 @@
      * Returns the space increment.
      * @return the space increment
      */
-    public int getSpaceIncrement(){
+    public int getSpaceIncrement() {
         return this.spaceIncrement;
     }
 
@@ -294,7 +294,7 @@
      * Returns the em space increment.
      * @return the em space increment
      */
-    public int getEmSpaceIncrement(){
+    public int getEmSpaceIncrement() {
         return this.emSpaceIncrement;
     }
 
Index: src/java/org/apache/fop/afp/fonts/DoubleByteFont.java
===================================================================
--- src/java/org/apache/fop/afp/fonts/DoubleByteFont.java	(revision 908040)
+++ src/java/org/apache/fop/afp/fonts/DoubleByteFont.java	(working copy)
@@ -1,90 +0,0 @@
-/*
- * 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.afp.fonts;
-
-import java.util.Set;
-
-/**
- * Implementation of AbstractOutlineFont that supports double-byte fonts (CID Keyed font (Type 0)).
- * The width of characters that are not prescribed a width metrics in the font resource use
- * a fallback width.  The default width is 1 em.  A character can be supplied and queried for the
- *  fallback width of all non-ideograph characters.<p />
- */
-public class DoubleByteFont extends AbstractOutlineFont {
-
-    //private static final Log LOG = LogFactory.getLog(DoubleByteFont.class);
-
-    //See also http://unicode.org/reports/tr11/ which we've not closely looked at, yet
-    //TODO the Unicode block listed here is probably not complete (ex. Hiragana, Katakana etc.)
-    private static final Set IDEOGRAPHIC = new java.util.HashSet();
-    static {
-        IDEOGRAPHIC.add(Character.UnicodeBlock.CJK_COMPATIBILITY_IDEOGRAPHS);
-        //IDEOGRAPHIC.add(Character.UnicodeBlock.CJK_COMPATIBILITY_IDEOGRAPHS_SUPPLEMENT); //Java 1.5
-        IDEOGRAPHIC.add(Character.UnicodeBlock.CJK_UNIFIED_IDEOGRAPHS);
-        IDEOGRAPHIC.add(Character.UnicodeBlock.CJK_UNIFIED_IDEOGRAPHS_EXTENSION_A);
-        //IDEOGRAPHIC.add(Character.UnicodeBlock.CJK_UNIFIED_IDEOGRAPHS_EXTENSION_B); //Java 1.1
-    }
-
-    /**
-     * Constructor for an double-byte outline font.
-     * @param name the name of the font
-     * @param charSet the character set
-     */
-    public DoubleByteFont(String name, CharacterSet charSet) {
-        super(name, charSet);
-    }
-
-    /** {@inheritDoc} */
-    public int getWidth(int character, int size) {
-        int charWidth;
-        try {
-            charWidth = charSet.getWidth(character);
-        } catch (IllegalArgumentException e) {
-            //  We shall try and handle characters that have no mapped width metric in font resource
-            charWidth = -1;
-        }
-
-        if (charWidth == -1) {
-            charWidth = inferCharWidth(character);
-        }
-        return charWidth * size;
-    }
-
-    private int inferCharWidth(int character) {
-
-        //Is this character an ideograph?
-        boolean isIdeographic = false;
-        Character.UnicodeBlock charBlock = Character.UnicodeBlock.of((char)character);
-        if (charBlock == null) {
-            isIdeographic = false;
-        } else if (IDEOGRAPHIC.contains(charBlock)) {
-            isIdeographic = true;
-        } else { //default
-            isIdeographic = false;
-        }
-
-        if (isIdeographic) {
-            return charSet.getEmSpaceIncrement();
-        } else {
-            return charSet.getSpaceIncrement();
-        }
-    }
-
-}
Index: src/java/org/apache/fop/afp/fonts/MetricFallbackStrategy.java
===================================================================
--- src/java/org/apache/fop/afp/fonts/MetricFallbackStrategy.java	(revision 0)
+++ src/java/org/apache/fop/afp/fonts/MetricFallbackStrategy.java	(revision 0)
@@ -0,0 +1,112 @@
+/*
+ * 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.afp.fonts;
+
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+
+/**
+ * A configurable font metric fallback strategy.
+ * Instances are parametrised by block and character fallback mappings.
+ *
+ *  Factory methods allow initialization with xml configuration.
+ *
+ */
+public class MetricFallbackStrategy implements IMetricFallbackStrategy {
+
+    private  Map/*<Character.UnicodeBlock, Double>*/ blockMap;
+    private  Map/*<Character.UnicodeBlock, Double>*/ charMap;
+
+    /**
+     * Constructor.
+     * @param blockConfig maps unicode block names to a fallback scaling factor.
+     * @param charConfig maps character codpoint to a fallback scaling factor.
+     * @throws parametrized incorrectly
+     */
+    protected MetricFallbackStrategy(Map/*<String, Double>*/ blockConfig,
+            Map/*<Integer, Double>*/ charConfig)
+    throws Exception {
+
+        this.blockMap = configureBlockMap(blockConfig);
+        //the integrity of the codepoints is not checked
+        this.charMap = new HashMap(charConfig);
+    }
+
+
+
+
+
+    /**
+     *
+     * @param blockConfig
+     * @return map of Character.UnicodeBlock to scale factor
+     */
+    private Map/*<Character.UnicodeBlock, Double>*/
+                    configureBlockMap(Map/*<String, Double>*/ blockConfig)
+        throws Exception {
+        HashMap map = new HashMap();
+        for (Iterator/*<String>*/ it = blockConfig.keySet().iterator(); it.hasNext();) {
+            String blockName = (String)it.next();
+            Character.UnicodeBlock block;
+            try {
+                 block = Character.UnicodeBlock.forName(blockName);
+            } catch (IllegalArgumentException e) {
+                //The calling code should handle explicitly handle bad configuration
+                throw new Exception("Unicode block name '"+blockName+"' not recognised");
+            }
+            Double scaleFactor = (Double)blockConfig.get(blockName);
+            map.put(block, scaleFactor);
+        }
+
+        return map;
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+
+    public int getWidth(int character, CharacterSet charSet) {
+
+        //Does character hava a fallback?
+        Double scaleFactor = (Double)charMap.get(Integer.valueOf(character));
+        if (scaleFactor != null) {
+            return (int)(charSet.getEmSpaceIncrement() * scaleFactor.doubleValue());
+        }
+
+        //Does the character's unicode block have a fallback?
+        Character.UnicodeBlock block = Character.UnicodeBlock.of(character);
+        if (block != null) {
+            scaleFactor = (Double)blockMap.get(block);
+            if (scaleFactor != null) {
+                return (int)(charSet.getEmSpaceIncrement() * scaleFactor.doubleValue());
+            }
+        } else {
+            throw new IllegalArgumentException("" + character + " is an illegal codepoint");
+        }
+
+        return charSet.getSpaceIncrement();
+    }
+
+
+
+}

Property changes on: src/java/org/apache/fop/afp/fonts/MetricFallbackStrategy.java
___________________________________________________________________
Added: svn:eol-style
   + native

Index: src/java/org/apache/fop/afp/fonts/DefaultMetricFallbackStrategy.java
===================================================================
--- src/java/org/apache/fop/afp/fonts/DefaultMetricFallbackStrategy.java	(revision 0)
+++ src/java/org/apache/fop/afp/fonts/DefaultMetricFallbackStrategy.java	(revision 0)
@@ -0,0 +1,70 @@
+/*
+ * 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.afp.fonts;
+
+import java.util.Set;
+
+/**
+ *  A default implementation
+ */
+public class DefaultMetricFallbackStrategy implements IMetricFallbackStrategy {
+
+
+    private static final Set IDEOGRAPHIC = new java.util.HashSet();
+    static {
+        IDEOGRAPHIC.add(Character.UnicodeBlock.CJK_COMPATIBILITY_IDEOGRAPHS);
+      //IDEOGRAPHIC.add(Character.UnicodeBlock.CJK_COMPATIBILITY_IDEOGRAPHS_SUPPLEMENT); //Java 1.5
+        IDEOGRAPHIC.add(Character.UnicodeBlock.CJK_UNIFIED_IDEOGRAPHS);
+        IDEOGRAPHIC.add(Character.UnicodeBlock.CJK_UNIFIED_IDEOGRAPHS_EXTENSION_A);
+      //IDEOGRAPHIC.add(Character.UnicodeBlock.CJK_UNIFIED_IDEOGRAPHS_EXTENSION_B); //Java 1.1
+    }
+
+
+    /**
+     * Default constructor.  Should be instantiated by FallbackStrategyFactory.
+     */
+    protected DefaultMetricFallbackStrategy() { }
+
+
+   /**
+    * {@inheritDoc}
+    */
+    public int getWidth(int character, CharacterSet charSet) {
+
+        //Is this character an ideograph?
+        boolean isIdeographic = false;
+        Character.UnicodeBlock charBlock = Character.UnicodeBlock.of(character);
+        if (charBlock == null) {
+            isIdeographic = false;
+        } else if (IDEOGRAPHIC.contains(charBlock)) {
+            isIdeographic = true;
+        } else { //default
+            isIdeographic = false;
+        }
+
+        if (isIdeographic) {
+            return charSet.getEmSpaceIncrement();
+        } else {
+            return charSet.getSpaceIncrement();
+        }
+    }
+
+
+}

Property changes on: src/java/org/apache/fop/afp/fonts/DefaultMetricFallbackStrategy.java
___________________________________________________________________
Added: svn:eol-style
   + native

Index: src/documentation/content/xdocs/trunk/output.xml
===================================================================
--- src/documentation/content/xdocs/trunk/output.xml	(revision 908040)
+++ src/documentation/content/xdocs/trunk/output.xml	(working copy)
@@ -555,7 +555,7 @@
         <li>IBM CID-keyed (Type 0) fonts</li>
         <li>FOP built-in Base14 fonts</li>
       </ol>
-      <p>A typical raster font configuration looks like:</p>
+      <p>A typical <strong>raster</strong> font configuration looks like:</p>
 <source><![CDATA[      <!-- This is an example of mapping actual IBM raster fonts / code pages to a FOP font -->
         <font>
         <!-- The afp-font element defines the IBM code page, the matching Java encoding and the
@@ -582,7 +582,7 @@
         <font-triplet name="Times-Roman" style="normal" weight="normal"/>
         <font-triplet name="TimesNewRoman" style="normal" weight="normal"/>
       </font>]]></source>
-      <p>An outline font configuration is simpler as the individual font size entries are not required.
+      <p>An <strong>outline</strong> font configuration is simpler as the individual font size entries are not required.
       However, the characterset definition is now required within the afp-font element.</p>
 <source><![CDATA[      <font>
           <afp-font type="outline" codepage="T1V10500" encoding="Cp500" characterset="CZH200  "
@@ -601,7 +601,7 @@
         supported for the time being, but you should move to using the more flexible "base-uri"
         attribute so you can profit from the power of URI resolvers.
       </note>
-      <p>A CID-keyed font (Type 0, double-byte outline font) configuration is much the same as an outline font.
+      <p>A <strong>CID-keyed</strong> font (Type 0, double-byte outline font) configuration is much the same as an outline font.
       However, the characterset definition is now required within the afp-font element.</p>
 <source><![CDATA[      <font>
           <afp-font type="CIDKeyed" characterset="CZJHMNU" 
@@ -611,8 +611,91 @@
       </font>
 ]]></source>
       <p>
-Note that the value of the encoding attribute in the example is the double-byte encoding 'UnicodeBigUnmarked' (UTF-16BE).
-      </p>
+Note that the value of the encoding attribute in the example is the double-byte encoding 'UnicodeBigUnmarked' (UTF-16BE).</p>
+<p>
+CIDKeyed fonts can be configured with a font metric fallback strategy that provides an alternative font metric substitution scheme for characters that are missing metric information in the font resource.
+The following is a complete example of a fallback strategy declaration.</p>
+
+<p>
+
+</p>
+
+<source><![CDATA[       <fallback-strategy>
+            <block name="HIRAGANA" scale-factor="0.75" /> 
+            <character char="u+3044" scale-factor="1" />
+            <character char="に" scale-factor="1" />
+
+            <block name="...
+
+        </fallback-strategy>
+]]></source>
+<p>
+When a character is matched by the fallback strategy the substituted width metric of that character becomes <i>scale-factor*em</i>.  When no match is found the space width is used.
+A match is first checked for at the  character level, configured by the character elements.  If no match is found for this character a check is done at block, configured by the block elements.
+The character element configures the fallback strategy to target individual characters.  Characters can be specified literally or by the hexidecimal codepoint in the format u+XXXX.
+The block element configures the fallback strategy to target all characters within a unicode block. The block name must match an instance of the Character.UnicodeBlock Java class, e.g. <i>ARMENIAN, CYRILLIC, CJK_UNIFIED_IDEOGRAPHS_EXTENSION_A </i> 
+</p>
+<p>
+Fallback strategies can be assigned to CID-Keyed fonts in three ways.
+</p>
+<p>
+1 - Reference a strategy declared under <i>fonts</i>.  The configuration looks like
+</p>
+<source><![CDATA[       <fonts>
+            ...
+            <fallback-strategy name="strat 1">
+                ...
+            </fallback-strategy>
+            ...
+             <font>
+                <afp-font type=... >
+                    <fallback-strategy ref="strat 1" />
+                </afp-font>
+            </font>
+            ...
+        </fonts>
+]]></source>  
+<p>
+2 - Referencing an external file.
+</p>
+<p>
+<i>path/to/fallback_strat.xml</i>
+</p>
+<source><![CDATA[       <?xml version="1.0"?>
+        <fallback-strategy>
+            ...
+        </fallback-strategy>
+]]></source>
+<p>
+<i>fop.xconf</i>
+</p>
+<source><![CDATA[       ...    
+        <font>
+            <afp-font type=... >
+                <fallback-strategy url="path/to/fallback_strat.xml" />
+            </afp-font>
+        </font>
+        ...
+]]></source>
+<p>
+The file name is relative to the FOP runtime directory.  
+FOP will load the configuration the first time that the metrics are required.
+</p>
+<p>
+3 - Define the strategy inside <i>afp-font</i>.
+</p>
+
+ 
+<source><![CDATA[      <font>
+            <afp-font type=... >
+                <fallback-strategy>
+                    ...
+                </fallback-strategy>
+           </afp-font>
+             ...
+        </font>
+]]></source>
+
       <p>Experimentation has shown that the font metrics for the FOP built-in Base14 fonts are actually
       very similar to some of the IBM outline and raster fonts. In cases were the IBM font files are not
       available the base-uri attribute in the afp-font element can be replaced by a base14-font attribute 
