Esempio n. 1
0
    /// <summary>
    /// Writes a Glyphs to the content stream.
    /// </summary>
    private void WriteGlyphs(Glyphs glyphs)
    {
      WriteSaveState("begin Glyphs", glyphs.Name);

      // Transform also affects clipping and opacity mask
      bool transformed = glyphs.RenderTransform != null;
      if (transformed)
        WriteRenderTransform(glyphs.RenderTransform);

      bool clipped = glyphs.Clip != null;
      if (clipped)
        WriteClip(glyphs.Clip);

      if (glyphs.Opacity < 1)
        MultiplyOpacity(glyphs.Opacity);

      if (glyphs.OpacityMask != null)
        WriteOpacityMask(glyphs.OpacityMask);

      XForm xform = null;
      XImage ximage = null;
      RealizeFill(glyphs.Fill, ref xform, ref ximage);
      RealizeFont(glyphs);

      double x = glyphs.OriginX;
      double y = glyphs.OriginY;


      //switch (format.Alignment)
      //{
      //  case XStringAlignment.Near:
      //    // nothing to do
      //    break;

      //  case XStringAlignment.Center:
      //    x += (rect.Width - width) / 2;
      //    break;

      //  case XStringAlignment.Far:
      //    x += rect.Width - width;
      //    break;
      //}

      PdfFont realizedFont = this.graphicsState.realizedFont;
      Debug.Assert(realizedFont != null);
      realizedFont.AddChars(glyphs.UnicodeString);

      TrueTypeDescriptor descriptor = realizedFont.FontDescriptor.descriptor;

      //if (bold && !descriptor.IsBoldFace)
      //{
      //  // TODO: emulate bold by thicker outline
      //}

      //if (italic && !descriptor.IsBoldFace)
      //{
      //  // TODO: emulate italic by shearing transformation
      //}

      string s2 = "";
      string s = glyphs.UnicodeString;
      if (!String.IsNullOrEmpty(s))
      {
        for (int idx = 0; idx < s.Length; idx++)
        {
          char ch = s[idx];
          int glyphID = 0;
          if (descriptor.fontData.cmap.symbol)
          {
            glyphID = (int)ch + (descriptor.fontData.os2.usFirstCharIndex & 0xFF00);
            glyphID = descriptor.CharCodeToGlyphIndex((char)glyphID);
          }
          else
            glyphID = descriptor.CharCodeToGlyphIndex(ch);
          s2 += (char)glyphID;
        }
      }
      s = s2;

      byte[] bytes = PdfEncoders.RawUnicodeEncoding.GetBytes(s);
      bytes = PdfEncoders.FormatStringLiteral(bytes, true, false, true, null);
      string text = PdfEncoders.RawEncoding.GetString(bytes);
      XPoint pos = new XPoint(x, y);
      AdjustTextMatrix(ref pos);
      WriteLiteral("{0:0.###} {1:0.###} Td {2} Tj\n", pos.x, pos.y, text);
      //PdfEncoders.ToStringLiteral(s, PdfStringEncoding.RawEncoding, null));

      WriteRestoreState("end Glyphs", glyphs.Name);
    }
    //    string realizedFontName = String.Empty;
    //    double realizedFontSize = 0;

    public void RealizeFont(Glyphs glyphs)
    {
      // So far rendering mode 0 only
      //RealizeBrush(brush, this.renderer.colorMode); // this.renderer.page.document.Options.ColorMode);

      try
      {
        // Get fixed payload which contains the font manager
        FixedPage fpage = glyphs.GetParent<FixedPage>();
        if (fpage == null)
        {
          GetType();
          this.realizedFont = new PdfFont(null);
        }
        FixedPayload payload = fpage.Document.Payload;

        // Get the font object.
        // Important: font.PdfFont is not yet defined here on the first call
        string uriString = glyphs.FontUri;
        Font font = payload.GetFont(uriString);

        // Get the page local resource name and define font.PdfFont if it is not yet defined
        string fontName = writer.GetFontName(font);
        this.realizedFont = font.PdfFont;

        //if (fontName != this.realizedFontName || this.realizedFontSize != font.Size)
        {
          //this.writer.WriteLiteral("{0} {1:0.###} Tf\n", fontName, -glyphs.FontRenderingEmSize);
          this.writer.WriteLiteral("{0} {1:0.###} Tf\n", fontName, -glyphs.FontRenderingEmSize);

          //this.realizedFontName = fontName;
          //this.realizedFontSize = font.Size;
        }
      }
      catch (Exception ex)
      {
        Debug.WriteLine(ex.Message);
      }
    }
Esempio n. 3
0
    /// <summary>
    /// Parses a Glyphs element.
    /// </summary>
    Glyphs ParseGlyphs()
    {
      Debug.Assert(this.reader.Name == "Glyphs");
      Glyphs glyphs = new Glyphs();
      while (MoveToNextAttribute())
      {
        switch (this.reader.Name)
        {
          case "BidiLevel":
            glyphs.BidiLevel = Int32.Parse(this.reader.Value);
            break;

          case "CaretStops":
            glyphs.CaretStops = this.reader.Value;
            break;

          case "DeviceFontName":
            glyphs.DeviceFontName = this.reader.Value;
            break;

          case "Fill":
            glyphs.Fill = ParseBrush(this.reader.Value); 
            break;

          case "FontRenderingEmSize":
            glyphs.FontRenderingEmSize = ParseDouble(this.reader.Value);
            break;

          case "FontUri":
            glyphs.FontUri = this.reader.Value;
            break;

          case "OriginX":
            glyphs.OriginX = ParseDouble(this.reader.Value);
            break;

          case "OriginY":
            glyphs.OriginY = ParseDouble(this.reader.Value);
            break;

          case "IsSideways":
            glyphs.IsSideways = ParseBool(this.reader.Value);
            break;

          case "Indices":
            glyphs.Indices = new GlyphIndices(this.reader.Value);
            break;

          case "UnicodeString":
            glyphs.UnicodeString = this.reader.Value;
            break;

          case "StyleSimulations":
            glyphs.StyleSimulations = ParseEnum<StyleSimulations>(this.reader.Value);
            break;

          case "RenderTransform":
            glyphs.RenderTransform = ParseMatrixTransform(this.reader.Value);
            break;

          case "Clip":
            glyphs.Clip = ParsePathGeometry(this.reader.Value);
            break;

          case "Opacity":
            glyphs.Opacity = ParseDouble(this.reader.Value);
            break;

          case "Name":
            glyphs.Name = this.reader.Value;
            break;

          case "FixedPage.NavigateUri":
            glyphs.FixedPage_NavigateUri = this.reader.Value;
            break;

          case "xml:lang":
            glyphs.lang = this.reader.Value;
            break;

          case "x:Key":
            glyphs.Key = this.reader.Value;
            break;

          default:
            UnexpectedAttribute(this.reader.Name);
            break;
        }
      }
      // TODO Glyphs
      MoveBeyondThisElement();
      return glyphs;
    }
Esempio n. 4
0
 /// <summary>
 /// Makes the specified font and brush to the current graphics objects.
 /// </summary>
 void RealizeFont(Glyphs glyphs)
 {
   if (this.streamMode != StreamMode.Text)
   {
     this.streamMode = StreamMode.Text;
     WriteLiteral("BT\n");
     // Text matrix is empty after BT
     this.graphicsState.realizedTextPosition = new XPoint();
   }
   this.graphicsState.RealizeFont(glyphs);
 }
Esempio n. 5
0
 private void WriteGlyphs_GlyphIndicesAndDistanceOnly(Glyphs glyphs, string text)
 {
   // TODO:
 }
Esempio n. 6
0
    private void WriteGlyphs_ClusterMapping(Glyphs glyphs, string text)
    {
      GlyphIndices indices = glyphs.Indices;
      int chCount = text.Length;
      //int chidx = 0;
      int glCont = indices.Count;
      int glidx = 0;
      bool stop = false;
      do
      {
        GlyphIndices.GlyphMapping mapping = indices[glidx];

//        if (mapping.HasClusterCount
      }
      while (!stop);
    }
Esempio n. 7
0
 private void WriteGlyphs_None(Glyphs glyphs, string text)
 {
   // TODO:
 }
Esempio n. 8
0
 private void WriteGlyphs_DistanceOnly(Glyphs glyphs, string text)
 {
   // TODO:
 }
Esempio n. 9
0
    // ...on the way to handle Indices...
    private void WriteGlyphs_Indices1(Glyphs glyphs, string text)
    {
      GlyphIndicesComplexity complexity = glyphs.Indices.Complexity;
      complexity = GlyphIndicesComplexity.ClusterMapping;
      switch (complexity)
      {
        case GlyphIndicesComplexity.None:
          break;

        case GlyphIndicesComplexity.DistanceOnly:
          break;

        case GlyphIndicesComplexity.GlyphIndicesAndDistanceOnly:
          break;

        case GlyphIndicesComplexity.ClusterMapping:
          WriteGlyphs_ClusterMapping(glyphs, text);
          break;
      }
    }
Esempio n. 10
0
        /// <summary>
        /// Parses a Canvas element.
        /// </summary>
        Canvas ParseCanvas()
        {
            Debug.Assert(this.reader.Name == "Canvas");
            Canvas canvas = new Canvas();

            try
            {
                bool isEmptyElement = this.reader.IsEmptyElement;
                while (MoveToNextAttribute())
                {
                    switch (this.reader.Name)
                    {
                    case "Name":
                        canvas.Name = this.reader.Value;
                        break;

                    case "RenderTransform":
                        canvas.RenderTransform = ParseMatrixTransform(this.reader.Value);
                        break;

                    case "Clip":
                        canvas.Clip = ParsePathGeometry(this.reader.Value);
                        break;

                    case "Opacity":
                        canvas.Opacity = ParseDouble(this.reader.Value);
                        break;

                    case "OpacityMask":
                        canvas.OpacityMask = ParseBrush(this.reader.Value);
                        break;

                    case "RenderOptions.EdgeMode":
                        canvas.RenderOptions_EdgeMode = this.reader.Value;
                        break;

                    case "FixedPage.NavigateUri":
                        canvas.FixedPage_NavigateUri = this.reader.Value;
                        break;

                    case "AutomationProperties.HelpText":
                        canvas.AutomationProperties_HelpText = this.reader.Value;
                        break;

                    case "AutomationProperties.Name":
                        canvas.AutomationProperties_Name = this.reader.Value;
                        break;

                    case "xml:lang":
                        canvas.lang = this.reader.Value;
                        break;

                    case "xmlns:x":
                        break;

                    default:
                        UnexpectedAttribute(this.reader.Name);
                        break;
                    }
                }
                if (!isEmptyElement)
                {
                    MoveToNextElement();
                    while (this.reader.IsStartElement())
                    {
                        switch (this.reader.Name)
                        {
                        case "Canvas.Resources":
                            MoveToNextElement();
                            ResourceDictionary rd = new ResourceDictionary();
                            canvas.Resources  = rd;
                            rd.Parent         = canvas;
                            rd.ResourceParent = ResourceDictionaryStack.Current;
                            ResourceDictionaryStack.Push(rd);
                            ParseResourceDictionary(rd);
                            MoveToNextElement();
                            break;

                        case "Canvas.RenderTransform":
                            MoveToNextElement();
                            canvas.RenderTransform = ParseMatrixTransform();
                            MoveToNextElement();
                            break;

                        case "Canvas.Clip":
                            MoveToNextElement();
                            canvas.Clip = ParsePathGeometry();
                            break;

                        case "Canvas.OpacityMask":
                            MoveToNextElement();
                            canvas.OpacityMask        = ParseBrush();
                            canvas.OpacityMask.Parent = canvas;
                            break;

                        case "Path":
                        {
                            PdfSharp.Xps.XpsModel.Path path = ParsePath();
#if DEBUG
                            if (!String.IsNullOrEmpty(path.Name))
                            {
                                Debug.WriteLine("Path: " + path.Name);
                            }
#endif
                            canvas.Content.Add(path);
                            path.Parent = canvas;
                        }
                        break;

                        case "Glyphs":
                        {
                            PdfSharp.Xps.XpsModel.Glyphs glyphs = ParseGlyphs();
                            canvas.Content.Add(glyphs);
                            glyphs.Parent = canvas;
                        }
                        break;

                        case "Canvas":
                        {
                            PdfSharp.Xps.XpsModel.Canvas canvas2 = ParseCanvas();
                            canvas.Content.Add(canvas2);
                            canvas2.Parent = canvas;
                        }
                        break;

                        case "mc:AlternateContent":
                        case "mc:Choice":
                            MoveToNextElement();
                            //canvas.Content.Add(ParseCanvas());
                            break;

                        default:
                            Debugger.Break();
                            break;
                        }
                    }
                }
                MoveToNextElement();
            }
            finally
            {
                // If the current ResourceDictionary is from this Canvas, pop it.
                if (canvas != null && canvas.Resources != null)
                {
                    if (Object.ReferenceEquals(canvas.Resources, ResourceDictionaryStack.Current))
                    {
                        ResourceDictionaryStack.Pop();
                    }
                }
            }
            return(canvas);
        }
    /// <summary>
    /// This is just a draft to see what to do in detail.
    /// </summary>
    private void WriteGlyphs_ClusterMapping(Glyphs glyphs)
    {
      string unicodeString = glyphs.UnicodeString;
#if DEBUG_
      if (!String.IsNullOrEmpty(unicodeString))
      {
        if (unicodeString.StartsWith("abc"))
          GetType();
      }
#endif

      bool boldSimulation = (glyphs.StyleSimulations & StyleSimulations.BoldSimulation) == StyleSimulations.BoldSimulation;
      double boldSimulationFactor = 1;
      if (boldSimulation)
        boldSimulationFactor = 1;

      bool RightToLeft = glyphs.BidiLevel % 2 == 1;  // TODOWPF: why is this a level?? what means "bidirectional nesting"?

      GlyphIndices indices = glyphs.Indices;
      if (indices == null)
        indices = new GlyphIndices();
      int codeIdx = 0;
      int codeCount = String.IsNullOrEmpty(unicodeString) ? 0 : unicodeString.Length;
      int glyphCount = indices.Count;
      int glyphIdx = 0;
      bool stop = false;

      PdfFont realizedFont = this.graphicsState.realizedFont;
      OpenTypeDescriptor descriptor = realizedFont.FontDescriptor.descriptor;
      int glyphIndex;

      double x = glyphs.OriginX;
      double y = glyphs.OriginY;
      XPoint pos = new XPoint(x, y); // accumulation may lead to rounding error -> check it!
      double uOffset = 0;
      double vOffset = 0;

      StringBuilder outputText = new StringBuilder();
      double accumulatedWidth = 0;
      int outputGlyphCount = 0;
      bool mustRender = false;
      bool hasOffset = false;

      do
      {
        GlyphIndices.GlyphMapping clusterMapping = new GlyphIndices.GlyphMapping(42);
        if (glyphIdx < glyphCount)
          clusterMapping = indices[glyphIdx];

        for (int clusterGlyphIdx = 0; clusterGlyphIdx < clusterMapping.ClusterGlyphCount; clusterGlyphIdx++)
        {
          GlyphIndices.GlyphMapping mapping = new GlyphIndices.GlyphMapping(42);
          if (glyphIdx + clusterGlyphIdx < glyphCount)
            mapping = indices[glyphIdx + clusterGlyphIdx];

          Debug.Assert(mustRender == false);

          // Determine whether to render accumulated glyphs
          if (outputGlyphCount > 0 && (hasOffset || mapping.HasAdvanceWidthOrOffset))
          {
            outputText.Append('>');

            WriteLiteral("{0:0.####} {1:0.####} Td {2}Tj\n", pos.x, pos.y, outputText.ToString());

            //double width = descriptor.GlyphIndexToPdfWidth(glyphIndex);
            //if (!PdfSharp.Internal.DoubleUtil.IsNaN(mapping.AdvanceWidth))
            //  width = mapping.AdvanceWidth * 10;
            //pos = new XPoint(accumulatedWidth + width / 1000 * glyphs.FontRenderingEmSize, 0);
            pos = new XPoint(accumulatedWidth, 0);

            // reset values
            accumulatedWidth = 0;
            outputGlyphCount = 0;
            outputText.Length = 0;
            mustRender = false;
          }

          mustRender = mapping.HasAdvanceWidth;
          //mustRender = true;

          // Adjust former uOffset
          if (uOffset != 0)
          {
            pos.x -= uOffset;
            uOffset = 0;
            mustRender = true;
          }

          // Adjust position by current former uOffset
          if (mapping.HasUOffset)
          {
            uOffset = mapping.UOffset * glyphs.FontRenderingEmSize / 100;
            pos.x += uOffset;
            mustRender = true;
            hasOffset = true;
          }

          // Adjust former vOffset
          if (vOffset != 0)
          {
            pos.y += vOffset;
            vOffset = 0;
            mustRender = true;
          }

          // Adjust position by current former vOffset
          if (mapping.HasVOffset)
          {
            vOffset = mapping.VOffset * glyphs.FontRenderingEmSize / 100;
            pos.y -= vOffset;
            mustRender = true;
            hasOffset = true;
          }


          // get index of current glyph
          if (mapping.HasGlyphIndex)
            glyphIndex = mapping.GlyphIndex;
          else
            glyphIndex = descriptor.CharCodeToGlyphIndex(unicodeString[codeIdx]);

          // add glyph index to the fonts 'used glyph table'
          realizedFont.AddGlyphIndices(new string((char)glyphIndex, 1));

#if true
          if (outputGlyphCount == 0)
            outputText.Append('<');
          outputText.AppendFormat("{0:X2}{1:X2}", (byte)(glyphIndex >> 8), (byte)glyphIndex);
#else
          byte[] bytes = new byte[2] { (byte)(glyphIndex >> 8), (byte)glyphIndex };
          bytes = PdfEncoders.FormatStringLiteral(bytes, true, false, true, null);
          string output = PdfEncoders.RawEncoding.GetString(bytes);
#endif

          // At the end of the glyph run we must always render
          if (!mustRender)
            mustRender = codeIdx + clusterMapping.ClusterCodeUnitCount >= codeCount  // is it the last code unit cluster
              && glyphIdx + clusterGlyphIdx + 1 >= glyphCount;  // is it the last glyph index

          //mustRender = true;
          if (mustRender)
          {
            outputText.Append('>');

            WriteLiteral("{0:0.####} {1:0.####} Td {2}Tj\n", pos.x, pos.y, outputText.ToString());

            double width = descriptor.GlyphIndexToPdfWidth(glyphIndex);
            if (!PdfSharp.Internal.DoubleUtil.IsNaN(mapping.AdvanceWidth))
              width = mapping.AdvanceWidth * 10;
            pos = new XPoint(accumulatedWidth + width * boldSimulationFactor / 1000 * glyphs.FontRenderingEmSize, 0);

            // reset values
            accumulatedWidth = 0;
            outputGlyphCount = 0;
            outputText.Length = 0;
            mustRender = false;
          }
          else // deferred rendering
          {
            // accumulate width
            Debug.Assert(DoubleUtil.IsNaN(mapping.AdvanceWidth));
            double width = descriptor.GlyphIndexToPdfWidth(glyphIndex);
            width = width * boldSimulationFactor / 1000 * glyphs.FontRenderingEmSize;
            accumulatedWidth += width;

            outputGlyphCount++;
          }
        }
        codeIdx += clusterMapping.ClusterCodeUnitCount;
        glyphIdx += clusterMapping.ClusterGlyphCount;

        if (codeIdx >= codeCount && glyphIdx >= glyphCount)
          stop = true;
      }
      while (!stop);
    }
    /// <summary>
    /// Writes a Glyphs to the content stream.
    /// </summary>
    private void WriteGlyphs(Glyphs glyphs)
    {
      WriteSaveState("begin Glyphs", glyphs.Name);

      // Transform also affects clipping and opacity mask
      bool transformed = glyphs.RenderTransform != null;
      if (transformed)
        WriteRenderTransform(glyphs.RenderTransform);

      bool clipped = glyphs.Clip != null;
      if (clipped)
        WriteClip(glyphs.Clip);

      if (glyphs.Opacity < 1)
        MultiplyOpacity(glyphs.Opacity);

      if (glyphs.OpacityMask != null)
        WriteOpacityMask(glyphs.OpacityMask);

      XMatrix textMatrix = new XMatrix();

      textMatrix.TranslatePrepend(glyphs.OriginX, glyphs.OriginY);
      glyphs.OriginX = glyphs.OriginY = 0; // HACK: do not change model

      double emSize = glyphs.FontRenderingEmSize;
      textMatrix.ScalePrepend(glyphs.FontRenderingEmSize);
      glyphs.FontRenderingEmSize = 1; // HACK: do not change model


      bool boldSimulation = (glyphs.StyleSimulations & StyleSimulations.BoldSimulation) == StyleSimulations.BoldSimulation;

      // just a draft...
      if (boldSimulation)
      {
        boldSimulation = true;

        // draw black stroke if it is not a solid color brush
        XColor color = XColor.FromArgb(0, 0, 0);
        if (glyphs.Fill is SolidColorBrush)
        {
          SolidColorBrush brush = glyphs.Fill as SolidColorBrush;
          color = brush.Color;
        }
        WriteLiteral(String.Format(CultureInfo.InvariantCulture, "{0:0.###} {1:0.###} {2:0.###}  RG\n", color.R / 255.0, color.G / 255.0, color.B / 255.0));
        WriteLiteral("{0:0.###} w\n", emSize / 50);
      }

      if ((glyphs.StyleSimulations & StyleSimulations.ItalicSimulation) == StyleSimulations.ItalicSimulation)
      {
        textMatrix.SkewPrepend(-20, 0);
      }

      XForm xform = null;
      XImage ximage = null;
      RealizeFill(glyphs.Fill, ref xform, ref ximage);
      RealizeFont(glyphs);

      if (boldSimulation)
        WriteLiteral("2 Tr\n", 1);

      double x = glyphs.OriginX;
      double y = glyphs.OriginY;


      //switch (format.Alignment)
      //{
      //  case XStringAlignment.Near:
      //    // nothing to do
      //    break;

      //  case XStringAlignment.Center:
      //    x += (rect.Width - width) / 2;
      //    break;

      //  case XStringAlignment.Far:
      //    x += rect.Width - width;
      //    break;
      //}

      PdfFont realizedFont = this.graphicsState.realizedFont;
      Debug.Assert(realizedFont != null);
      realizedFont.AddChars(glyphs.UnicodeString);

      OpenTypeDescriptor descriptor = realizedFont.FontDescriptor.descriptor;

      //if (bold && !descriptor.IsBoldFace)
      //{
      //  // TODO: emulate bold by thicker outline
      //}

      //if (italic && !descriptor.IsBoldFace)
      //{
      //  // TODO: emulate italic by shearing transformation
      //}

#if true
      string s2 = "";
      string s = glyphs.UnicodeString;
      if (!String.IsNullOrEmpty(s))
      {
        int length = s.Length;
        for (int idx = 0; idx < length; idx++)
        {
          char ch = s[idx];
          int glyphID = 0;
          if (descriptor.fontData.cmap.symbol)
          {
            glyphID = (int)ch + (descriptor.fontData.os2.usFirstCharIndex & 0xFF00);
            glyphID = descriptor.CharCodeToGlyphIndex((char)glyphID);
          }
          else
            glyphID = descriptor.CharCodeToGlyphIndex(ch);
          s2 += (char)glyphID;
        }
      }
      s = s2;
#endif

      byte[] bytes = PdfEncoders.RawUnicodeEncoding.GetBytes(s);
      bytes = PdfEncoders.FormatStringLiteral(bytes, true, false, true, null);
      string text = PdfEncoders.RawEncoding.GetString(bytes);
      if (glyphs.IsSideways)
      {
        textMatrix.RotateAtPrepend(-90, new XPoint(x, y));
        XPoint pos = new XPoint(x, y);
        AdjustTextMatrix(ref pos);
        //WriteTextTransform(textMatrix);
        WriteLiteral("{0} Tj\n", text);
      }
      else
      {
#if true
        //if (glyphs.BidiLevel % 2 == 1)
        //  WriteLiteral("-1 Tc\n");

        if (!textMatrix.IsIdentity)
          WriteTextTransform(textMatrix);

        WriteGlyphsInternal(glyphs, null);
#else
        XPoint pos = new XPoint(x, y);
        AdjustTextMatrix(ref pos);
        WriteLiteral("{0:0.###} {1:0.###} Td {2} Tj\n", pos.x, pos.y, text);
        //PdfEncoders.ToStringLiteral(s, PdfStringEncoding.RawEncoding, null));
#endif
      }
      WriteRestoreState("end Glyphs", glyphs.Name);
    }
    // ...on the way to handle Indices...
    private void WriteGlyphsInternal(Glyphs glyphs, string text)
    {
      GlyphIndicesComplexity complexity = GlyphIndicesComplexity.None;
      if (glyphs.Indices != null)
        complexity = glyphs.Indices.Complexity;
      complexity = GlyphIndicesComplexity.ClusterMapping;
      switch (complexity)
      {
        case GlyphIndicesComplexity.None:
          break;

        case GlyphIndicesComplexity.DistanceOnly:
          WriteGlyphs_DistanceOnly(glyphs);
          break;

        case GlyphIndicesComplexity.GlyphIndicesAndDistanceOnly:
          break;

        case GlyphIndicesComplexity.ClusterMapping:
          WriteGlyphs_ClusterMapping(glyphs);
          break;
      }
    }