2012年1月13日金曜日

AIRで動的埋め込みフォントを縦書き表示できるか?

結論から言うと、できる!

動的に埋め込みフォントを読み込んで表示することはできた。
琴線探査: AIRで動的に埋め込みフォントを読み込むには?

そして、動的埋め込みフォントを表示する場合のクセも掴んだ。
琴線探査: AIRで外部埋め込みフォントを動的に読み込んで表示する時の原因不明の問題

最後の課題は、いかにして動的埋め込みフォントを縦書きで表示するかだ。

確認した限りSpark系のコンポーネントで唯一動的埋め込みフォントを表示できるLabelは、縦書きができないことがわかった。
琴線探査: SparkのLabelは縦書きできない!_| ̄|○

ここで、ひょっとしてSDKのバージョンが上がればRichText系でも表示できるかも知れないと思ったので、FB4.6で同じコードを動かしてみたが、表示できなかった_| ̄|○

Spark系にこだわる必要は無いし、RichText系のコンポーネントで表示できないのも仕方ない。ただ、縦書きはFTEではできないので、どうしてもTLFが必要だ。

そこで、RichText系に頼らずにTLFを使って表示することにした。こんな風。

<?xml version="1.0" encoding="utf-8"?>
<s:WindowedApplication xmlns:fx="http://ns.adobe.com/mxml/2009" 
                       xmlns:s="library://ns.adobe.com/flex/spark" 
                       xmlns:mx="library://ns.adobe.com/flex/mx"
                       minWidth="320" minHeight="320"
                       creationComplete="onCreationComplete();"
                       >
  
  <fx:Script>
    <![CDATA[
      import flash.text.engine.FontLookup;
      
      import flashx.textLayout.container.ContainerController;
      import flashx.textLayout.elements.ParagraphElement;
      import flashx.textLayout.elements.SpanElement;
      import flashx.textLayout.elements.TextFlow;
      import flashx.textLayout.formats.BlockProgression;
      import flashx.textLayout.formats.TextLayoutFormat;
      
      import mx.core.UIComponent;
      import mx.events.ResizeEvent;
      
      import spark.components.Label;
      import spark.components.RichText;
      
      protected function onCreationComplete():void {
        
        trace("onCreationComplete()");
        var url:String = "FontPack.swf";
        var urlLoader:URLLoader = new URLLoader();
        urlLoader.dataFormat = URLLoaderDataFormat.BINARY;
        urlLoader.addEventListener(Event.COMPLETE, onCompleteUrlLoader);
        urlLoader.load(new URLRequest(url));
        function onCompleteUrlLoader():void {
          
          var ba:ByteArray = urlLoader.data;
          trace("onCompleteUrlLoader() bytes=" + ba.length);        
          var lc:LoaderContext = new LoaderContext();
          lc.allowLoadBytesCodeExecution = true; //AIRではこれが必要
          lc.applicationDomain = ApplicationDomain.currentDomain;
          var loader:Loader = new Loader();
          loader.contentLoaderInfo.addEventListener(Event.COMPLETE, onCompleteLoader);
          loader.loadBytes(ba, lc);
          
          function onCompleteLoader(event:Event):void {
            
            //フォントの登録
            var FontPack:Class = ApplicationDomain.currentDomain.getDefinition("FontPack") as Class;
            Font.registerFont(FontPack.AquaFont);
            Font.registerFont(FontPack.Elenat);
            Font.registerFont(FontPack.MilkyWell);
            trace("onCompleteLoader() Loaded FontPack vernum=" + FontPack.vernum);
            
            //埋め込みフォントの登録リストを表示
            var embedFonts:Array = Font.enumerateFonts(false);
            for (var i:int = 0; i < embedFonts.length; i++) {
              var font:Font = embedFonts[i];
              trace("onCompleteLoader() : [" + i + "]" + " fontName=" + font.fontName + " fontStyle=" + font.fontStyle + " fontType=" + font.fontType);
            }
            
            //TextLayoutFormat構築
            var padding:int = 10;
            var tlf:TextLayoutFormat = new TextLayoutFormat();
            tlf.locale = "ja"; //これはやった方がいいらしい。縦書きで英語と日本語が混在するときに威力を発揮する。
            tlf.fontLookup = FontLookup.EMBEDDED_CFF;
            tlf.fontFamily = "あくあフォント";
            //tlf.fontFamily = "えれーな";
            //tlf.fontFamily = "MilkyWell";
            tlf.fontSize = 24;
            tlf.blockProgression = BlockProgression.RL;
            tlf.paddingBottom = padding;
            tlf.paddingLeft = padding;
            tlf.paddingRight = padding;
            tlf.paddingTop = padding;
            
            //TextFlow構築
            var se:SpanElement = new SpanElement();
            se.text = "Flex/AIRで外部埋め込みフォントを表示するテスト";
            var pa:ParagraphElement = new ParagraphElement();
            pa.addChild(se);
            var textFlow:TextFlow = new TextFlow();
            textFlow.hostFormat = tlf;
            textFlow.addChild(pa);
            
            //ターゲットスプライト構築
            var target:UIComponent = new UIComponent(); //UIComponentが必要。ContainerやCanvasは不可!
            target.percentWidth = 100;
            target.percentHeight = 100;
            target.addEventListener(ResizeEvent.RESIZE, onResizeTarget);
            function onResizeTarget():void {
              cc.setCompositionSize(target.width, target.height);
              textFlow.flowComposer.updateAllControllers(); //これをしないとCompositionSize(フォントの描画領域)が更新されない
            }
            vg.addElement(target);
            
            //テキスト表示用コントローラ(ターゲット)を追加
            var cc:ContainerController = new ContainerController(target);
            textFlow.flowComposer.addController(cc);
            
            //コントローラ更新
            textFlow.flowComposer.updateAllControllers(); //これをしないと文字が表示されない
            
            //これをしないとlabel1が埋め込みフォントで表示されない(何らかの更新イベントが必要だからだと思う)
            label1.setStyle("fontSize", 24);
            
            //動的埋め込みフォント読み込み後に追加するSparkLabel
            var label2:Label = new Label();
            label2.text = "label2";
            label2.setStyle("fontLookup", FontLookup.EMBEDDED_CFF);
            label2.setStyle("fontSize", 24);
            label2.setStyle("fontFamily", "えれーな");
            vg.addElement(label2);
            
          } //END onCompleteLoader()
          
        } //END onCompleteUrlLoader()
        
      } //END onCreationComplete()
      
    ]]>
  </fx:Script>
  
  <s:VGroup id="vg" width="100%" height="100%" gap="10" paddingBottom="5" paddingLeft="5" paddingRight="5" paddingTop="5">
    
    <!-- 初期段階では埋め込みフォントで表示されない -->
    <s:Label id="label1" text="label1" fontLookup="embeddedCFF" fontSize="23" fontFamily="MilkyWell"/>
    
    <!-- これをコメントアウトすると独自にTLFを使って動的埋め込みフォントを表示できるようにしたものもできなくなる -->
    <!--
    <s:RichText id="rt" fontSize="24" text="RichText"/>
    -->
    
  </s:VGroup>
  
</s:WindowedApplication>

実行するとこんな風。


というわけで、動的埋め込みフォントを縦書き表示することはできる!

RichTextを使うよりだいぶ('A`)マンドクセだけど、縦書きを実現するためだから仕方なし。

動的埋め込みフォント読み込み前にMXML側で追加したlabel1は、fontSizeなどのプロパティーを変更しないと埋め込みフォントで表示されないことがわかった。恐らく、何らかの更新イベントが必要なのだと思う。

動的埋め込みフォント読み込み後にAS側で追加したlabel2は、設定したとおりに埋め込みフォントで表示された。

ところで、一つ不可解な現象が。

上のコードでRichTextをコメントしてあるけれど、これをコメントアウトして実行すると、TLF系の埋め込みフォント表示ができなくなる。こんな風。


原因は不明。

追記12.01.16:TLF系の埋め込みフォント表示ができなくなるコンポーネントはRichTextだけではないことがわかった。今のところ分かっているものだけでもこれだけある。

・RichText
・RichEditableText
・TextInput
・NumericStepper