Re: Justification in HEAD
J.Pietschmann wrote: Thanks for taking the time to explain your thoughts they are appreciated. snip/ One point is that I didnt think Line BPs were kept past the call to addArea methods, which is AT construction and well before rendering. The TSAdjust properties is on the TextArea object which is part of the AreaTree. Summarizing: we have a bunch of strategies: - Keep data associated with adjustable spaces from layout for rendering, thereby avoiding recalculation This is what I'm going to do. Merely because from my company's point of view performance is more important than memory. We specialize in generating lots of 1-10 (approx) page documents. I also believe this is the solution that I am proposing to implement. - Discard the data as early as possible, thereby reducing peak memory usage - Use something in between: copy into a compact representation, or discard part of the data. I lean somewhat to the first strategy, because memory is usually more of a problem then bare performance. This appears to be a contradiction, did you mean the last strategy? I also have the gut feeling this approach makes integration of leader expansion easier. Of course, if someone implements several possiblities and runs benchmarks, or even makes it a user choice, I wont object. Chris
Re: Justification in HEAD
Chris Bowditch wrote: I lean somewhat to the first strategy, because memory is usually more of a problem then bare performance. This appears to be a contradiction, did you mean the last strategy? Well, I meant the second (free memory as early as possible). J.Pietschmann
Re: Justification in HEAD
J.Pietschmann wrote: Thanks for your responses, they are useful in helping my thought process. Well, the line may be parsed while rendering, which means you don't have to create area objects, roughly: StringTokenizer tok=new StringTokenizer(...); while( tok.hasMoreTokens ) { String word = tok.nextToken(); renderText(x,y,word); x+=width(word); x+=adjustedSpaceWidth; } An interesting idea... but hasnt this already been done in more detail in TextLM.getNextBreakPoss? So why should the renderer have to do it again (although in less complexity)? I would rather have layout do this, otherwise this logic would have to live in every renderer. There is a tradeoff between avoiding recomputing the word width and carrying it around for probably some significant time. I dont understand this bit fully. Are you saying its inefficient to carry around data items such as dAdjust, TSAdjust, etc? I would definitely say it is better than re-computing them in the renderer. Chris
Re: Justification in HEAD
Simon Pepping wrote: The trouble is renderText is being presented with a whole line at a time. It should be presented with smaller chunks if it is going to be able to add the TSAdjust space to each word space. Do you need to break the line is as many separate text areas as there are word spaces ( + 1 )? Well yes, but I'm open to alternative ideas. I also believe dAdjust is computed incorrectly. I'm going to change the dAdjust in LineLM.makeLineBreak to be targetWidth - realWidth instead of (targetWidth - realWidth) / realWidth. Have you got any ideas why dAdjust is computed this way? I guess it is supposed to be a relative, not an absolute length difference, so that it can be used as a factor. I have not followed the calculations in that much detail. Well thats what I thought, but relative factors still need to produce absolute results and realWidth isnt available to use as a multiplier in the TextLM.addAreas method. Chris
Re: Justification in HEAD
Chris Bowditch wrote: An interesting idea... but hasnt this already been done in more detail in TextLM.getNextBreakPoss? So why should the renderer have to do it again (although in less complexity)? I would rather have layout do this, otherwise this logic would have to live in every renderer. There is a tradeoff between avoiding recomputing the word width and carrying it around for probably some significant time. I dont understand this bit fully. Are you saying its inefficient to carry around data items such as dAdjust, TSAdjust, etc? I would definitely say it is better than re-computing them in the renderer. As you noticed, the TextLM.getNextBreakPoss examines the content character by character for calculating the break possiblities, thereby also keeping track of accumulated text width for the line. The break possiblities, or something else, could be marked whether they delimit adjustable space, refer to the x-offset or something equivalent and the text snippet and all passed to the renderer, thereby avoiding reparsing the line for adjustable space and recalculating offsets/widths. The point is that this data could as well be discarded after the line break is finalized. The most convenient way to keep it around until rendering without copying is as a list of small objects. Because redering doesn't start until a full page is laid out, this would lock up a significant amount memory. Whether it matters, compared to other problems, is yet to be determined. Summarizing: we have a bunch of strategies: - Keep data associated with adjustable spaces from layout for rendering, thereby avoiding recalculation - Discard the data as early as possible, thereby reducing peak memory usage - Use something in between: copy into a compact representation, or discard part of the data. I lean somewhat to the first strategy, because memory is usually more of a problem then bare performance. I also have the gut feeling this approach makes integration of leader expansion easier. Of course, if someone implements several possiblities and runs benchmarks, or even makes it a user choice, I wont object. J.Pietschmann
Re: Justification in HEAD
Simon Pepping wrote: Do you need to break the line is as many separate text areas as there are word spaces ( + 1 )? Well, the line may be parsed while rendering, which means you don't have to create area objects, roughly: StringTokenizer tok=new StringTokenizer(...); while( tok.hasMoreTokens ) { String word = tok.nextToken(); renderText(x,y,word); x+=width(word); x+=adjustedSpaceWidth; } There is a tradeoff between avoiding recomputing the word width and carrying it around for probably some significant time. J.Pietschmann
Re: Justification in HEAD
Simon Pepping wrote: Thanks for taking the time to reply. It is very useful to discuss this with someone who has an idea of how layout works. This loop only counts word spaces. Yes, I know, but I believe it should do more than that. Later the member iTSadjust is set on the text area: t.setTSadjust(iAdjust / iWScount). It seems that this is supposed to take care of space stretching, I do not know how. The renderer should add this to the X offset for every piece of text it places in the renderText method. It is missing ATM, but it is easy enough to add. I guess the renderer should know how to use this information. In my test runs, it is equal to 0, which explains the lack of justification. TSAdjust is set to zero because iAdjust is always zero in TextLM.addAreas. And this is always zero because it is based on a difference between min/opt/max of the ipdArea, but these are always the same in TextLM.getNextBreakPoss. I'm going to change this to set TSAdjust to dAdjust. I am not sure whether it is necessary to break up the text area into pieces. The trouble is renderText is being presented with a whole line at a time. It should be presented with smaller chunks if it is going to be able to add the TSAdjust space to each word space. The real calculations are happening much earlier, in the getNextBreakPoss loop. In LineLayoutManager.makeLineBreak, ipdAdjust and dAdjust are calculated based on the length of the line, and set as members on the new linebreak position. I also believe dAdjust is computed incorrectly. I'm going to change the dAdjust in LineLM.makeLineBreak to be targetWidth - realWidth instead of (targetWidth - realWidth) / realWidth. Have you got any ideas why dAdjust is computed this way? In the ensuing addAreas loop, LineLayoutManager.addAreas fetches these again from the linebreak position and sets them on the layout context. From there they are fetched by the above calculation and used in calculating iTSadjust -- with little succes at the moment. ipdAdjust seems to be for scaling between min, opt and max. dAdjust seems to be the scaling for justification. Yes I think you're right. These are my thoughts on the process. The whole thing is much clearer now Ive talked it over with you. Thanks once again, Chris
Re: Justification in HEAD
Chris Bowditch wrote: The renderer should add this to the X offset for every piece of text it places in the renderText method. It is missing ATM, but it is easy enough to add. Unfortunately, ther is more to justification than just expanding spaces. In the long term, you'll have to deal with leader expansion as well as start and end space for inlines and perhaps letter spacing. Leaders are particularly nasty because of they mey be aligned. It may be necessary to insert spaces in order to get alignment, but still avoiding inserting unnecessary spaces. For example in fo:blockfoofo:leader leader-alignment=reference-area ... it may be necessary to fiddle with letter spacing in foo or insert some space (not a space) after foo in order to get the leader aligned, while in fo:blockfoo barfo:leader leader-alignment=reference-area ... the space between foo and bar should be used. There's also the problem that the leaders have to be aligned *after* space justification, which is still broken in 0.20.5. I'm going to change this to set TSAdjust to dAdjust. Is this really a good idea? J.Pietschmann
Re: Justification in HEAD
Chris, On Fri, Jan 09, 2004 at 05:20:42PM +, Chris Bowditch wrote: Chris Bowditch wrote: The problem isnt that TextLM.getNextBreakPoss isnt finding BPs, problem is with addAreas, which, just skips over all the BPs and creates a single TextArea. This is evident from the following at the start of TextLM.addAreas: /* On first area created, add any leading space. * Calculate word-space stretch value. */ while (posIter.hasNext()) { LeafPosition tbpNext = (LeafPosition) posIter.next(); ai = (AreaInfo) vecAreaInfo.get(tbpNext.getLeafPos()); if (iStart == -1) { iStart = ai.iStartIndex; } iWScount += ai.iWScount; } This loop only counts word spaces. Later the member iTSadjust is set on the text area: t.setTSadjust(iAdjust / iWScount). It seems that this is supposed to take care of space stretching, I do not know how. I guess the renderer should know how to use this information. In my test runs, it is equal to 0, which explains the lack of justification. I am not sure whether it is necessary to break up the text area into pieces. The real calculations are happening much earlier, in the getNextBreakPoss loop. In LineLayoutManager.makeLineBreak, ipdAdjust and dAdjust are calculated based on the length of the line, and set as members on the new linebreak position. In the ensuing addAreas loop, LineLayoutManager.addAreas fetches these again from the linebreak position and sets them on the layout context. From there they are fetched by the above calculation and used in calculating iTSadjust -- with little succes at the moment. ipdAdjust seems to be for scaling between min, opt and max. dAdjust seems to be the scaling for justification. These are my thoughts on the process. Regards, Simon -- Simon Pepping email: [EMAIL PROTECTED] home page: http://www.leverkruid.nl public key: http://www.leverkruid.nl/personal/sp.asc fingerprint: E3BF 7295 9AA8 8B8A C01A 219D FAAC 088C 6B28 F549