Skip to main content
Participating Frequently
September 28, 2011
Question

Selection issue with Multiple containers when text re-flows

  • September 28, 2011
  • 4 replies
  • 2369 views

Hi,

I am building an EPUB reader in Flex 4.51. using TLF 2.0.3. I have text running across multiple containers. We add the controllers dynamically to ensure that there are as many containers as the content can have. Now, we updateAllControllers when status of a graphic element changes or when there's an increase in font size. So, after each activity we add more controllers if required. The text and images correctly reflow to the next container in this case. However, the issue comes with selection. If a piece of text reflows from one container and moves to another, when we try to select it, it doesn't highlight.

The SelectionChange event triggers and the values are mostly correct but no highlighing. We noticed that if we remove all controllers and recreate them, the issue is resolved. But, we cannot remove and add containers each time font size changes.

Kindly help and let me know where can the issue be? Remember that the text correctly reflows to containers and it's only the selection that doesn't work. This is a very common scenario for a reflowable content holder so I am sure I am missing something obvious. Please help.

This topic has been closed for replies.

4 replies

Participating Frequently
October 19, 2011

Hi Jin,

This helps. I can query TextFlow for all the <img> elements it has and update lineHeight there. For now, I had handled it in the getEffectiveLineHeight method overridden in ILG class.

I investigated further and found the exact reason for TextLine's parent being null. This was leading to several other issues with selection.

What happens in this scenario is that the TextLine added to the controller contains the correct reference to the TextFlowLine in it's user data BUT when we do a peekTextLine() on this TextFlowLine, it doesn't return the same TextLine and instead returns a stale TextLine, parent of which is null.

After spending a lot of time, I wasn't able to understand why exactly it is happening but added a small work around to fix:

  1. Before adding composed TextLine to Controller, I asked for the reference of TextFlowLine via TextLine's userdata
  2. I added a public property currentLine in TextFlowLine and set the TextLine into it.
  3. In peekTextLine, if currentLine is not null, I do not peek into TextBlock and simply return the TextLine.

This resolves the issue as the TextLine returned is always the correct one. I know that's the right place to do it but hopefully it'd help you suggest the area where fix needs to be done.

However, this does not help in resolving the issue with InlineGraphic element being removed by the succeeding controller. But the condition I added to the removeInlineGraphicElement seems to resolve it.  I know this is again a workaround but it works for me for now. The function looks like this:

     protected function removeInlineGraphicElement(parent:DisplayObjectContainer, inlineGraphicElement:DisplayObject):void

                    {

                              // We're removing the inline holder -- the float it owns should be in the visible list

                              CONFIG::debug { assert (parent != _container || _floatsInContainer.indexOf(DisplayObjectContainer(inlineGraphicElement).getChildAt(0)) >= 0, "Float *not* already in                                           container"); }

                              if (null != parent && inlineGraphicElement.parent == parent)

                              {

                                        if(parent.parent && parent.parent != container)

                                        {

                                                  return;

                                        }

                                        parent.removeChild(inlineGraphicElement);

                              }

                    }

I hope you come out with TLF 4.0 soon and have all these issues fixed there. I feel that there are certain areas where performance can be improved a lot by adding invalidation and commit cycles like Flex has, which would mean that everything gets processed lesser number of times and the user won't be able to make the difference. This is just how I thought.

Thanks for your time and I'd let you know I face any more issues.

Regards

Pulkit

Participating Frequently
October 14, 2011

Hi Jin,

I was initially using TLF 2 but tried porting to 3 and made change in the code as you suggested but it did not make any difference.

The App I am building is an extension of the sample Flex app you had shared on one of  the forums. It is a mobile app and am using Flex SDK 4.5.1. The TLF source is also embedded along as I had to comment / change out a few areas where Flex was giving compilation errors. These include using hardcoded string instead of constant in a constructor of few classes and commenting out ContextMenu code as mine is an AIR app and looks for NativeMenu instead of ContextMenu.

You can download the FXP from here:

http://s1.imfinity.com/TLFTest/TLF4EPub.fxp

There are plus and minus buttons at top and you can navigate to pages by tapping on left or right of the page.

Please choose Android from device configurations and Samsung Galaxy tab emulator from the list to emulate.

- As you make the text larger and it moves to new container, the selection stops working.

- As you reduce the font after increasing it such that image moves from one container to the one before it, the image would disappear.

Besides these, I am facing another issue on IPAD simulator where the first 2 lines appear behind the Image and are not visible. I have not been able to identify any solution for this till now. There is nothing specific about this issue to do with IPAD but just the dimensions of the device which make such a scenario happen.

I am not sure if I have put more than asked for but I thought I should give you as much information as I can. Hope you'd be able to have a look at this.

Thanks and Regards

Pulkit

Participating Frequently
October 18, 2011

Hi Jin,

After another deep dive into the TLF code, I came to know the cause of the problem where the image overlapped the text (the issue mentioned in my last reply). After looking at the code, I came to know that whenever TLF asks any FlowLeafElement for it's height via the getEffectiveLineHeight function. Now, this function multiplies the line height value by the TextFormat's lineheight property, if that is defined in percentage. The property was coming out to be 120%, which meant every TextLine used 20% more height than actual. In case of Image, this made a huge difference. And that's why in certain cases the Image obfuscated the previous line(s).

To fix this, I tried setting the TextFlowFormat's lineHeight property to 100% but this somehow made TLF stop resizing all the images, which I could not afford. So, just to verify, whether this was the issue or not. I removed the call to super.getEffectiveLineHeight from InlineGraphicElement and just returned the lineHeight from there without multiplying anything to it. And, as expected this fixed the issue.

I know that's just a work around and I'd need to find a better fix but first I want to understand why this multiplication by 120% after all the padding and margins?

Adobe Employee
October 19, 2011

The default value of lineHeight is 120% and TLF regards InlineGraphicElement as a charactor. So it will multiply 120% as well.

If you long for a 100% lineHeight for ILGs, before updateAllControllers(), you can go through the whole textflow leaf by leaf, and set lineHeight of ILG as 100% on your own. textflow.findFirstLeaf(); leaf.getNextLeaf();

To fix this, I tried setting the TextFlowFormat's lineHeight property to 100% but this somehow made TLF stop resizing all the images, which I could not afford.

Firstly, text will turn to be ugly if we change the default value of lineHeight to 100%. Of course, you can change that default value successfully, which won't cause any bug.  To modify, add or remove a format, the files as follows will be involved.

../textLayout/src/flashx/textLayout/formats/TextLayoutFormat.as

../textLayout/src/flashx/textLayout/formats/TextLayoutFormatInc.as

../textLayout/src/flashx/textLayout/formats/ITextLayoutFormat.as

Adobe Employee
September 30, 2011

I did not reproduce your new case. But based on your description, I think it is because TLF reuses some cached TextLines, rather than creates them from scratch.

When creating TextLines,

1. create TextElement to hold the text and GraphicElement to hold image,

2. feed the TextBlock.content with those TextElements and GraphicElements,

3. call TextBlock.creatTextLine() to create.

Thus, the parent of Loader is null because the process above has not been executed

We will be on vacation from Oct. 1st to 7th and will continue to look into the issue in Oct. 8th. Thanks!

Participating Frequently
September 30, 2011

Hi Jin,

It reproduces when Image is either at end of the content or at beginning of the content and moves to previous container. Just to correct you, parent of the loader is not null, it's the parent of it's parent sprite which is null and should have been a TextLine. I tried turning reusing of lines off but still the issue.

I think the issue is somewhere in ContainerController only. I will dig more to see if I can find anything.

Please note that if we decrease the font size further, the image starts appearing. I mean once the image is in the container and we make any change to the Flow, it starts appearing.

Thanks for looking into the issue. Have a nice vacation.

Adobe Employee
September 29, 2011

We found that it's a bug. The lines that cannot be highlighted have no 'parent'.

An FTE TextLine’s parent can be null in many cases.  The most common is that the TextLine is not on the DisplayList (not parented by a Sprite).  That’s a fairly normal case when long TextFlow’s are being scrolled.  Only the visible lines are on added to the Sprite. A variation is that the TextLine is “stale”.  It was generated again and the new version is on the DisplayList.  There is code in getTextLine (or possibly other TextFlowLine member functions) that is intended to handle this case. 

Hope it can help you to find a better workaround, because the fix for this bug will be in TLF 4.0.

Participating Frequently
September 29, 2011

Thanks Jin,

I had replaced the swc with the source code for 2.1 yesterday and found this to be the exact reasn for text not highlighting. The SelectionCache was not getting created because of Text line's parent being null in the TextFlowline class. I tried removing that condition and it worked fine. To compensate for the check being removed from here, I added a null check on ContainerController's container as I feel the textline's parent should be the same sprite as the controller's container. Works in general but would have to test it thoughrughly.  I also need to find if I can provide TextLine a parent when it is added to new container as a better approach.

It is no doubts a great framework and pretty flexible too. Surprisingly the performance is decent on mobiles. I really want to get it to work and bug you again in case I find any more issues.

I hope 4.0 will be officially supported for mobiles and provides easier ways to add custom tags.

Thanks again for the quick response.