pcorless opened a new pull request, #515:
URL: https://github.com/apache/pdfbox/pull/515

   # PDFBOX-6251: a CMap's own cid mappings lose to the ones it inherits via 
usecmap
   
   A CMap that starts with `usecmap` may redefine any code it inherits. It 
currently can't:
   `useCmap` merges the parent's `cidchar`/`cidrange` mappings into the same 
collections as the
   importing CMap's own, and since `usecmap` is read from the header, the 
parent's land in
   `codeToCid`/`codeToCidRanges` first. `toCID` scans the range list 
first-match, so an inherited
   range that covers a code beats the mapping the CMap declared for it.
   
   ```java
   new CMapParser().parsePredefined("ETenms-B5-H").toCID(0x41, 1);  // 13681, 
should be 34
   ```
   
   `ETenms-B5-H` exists only to do this override: it uses `ETen-B5-H`, then 
remaps 0x20-0x7E to the
   proportional latin CIDs 1-95 where the parent has the fullwidth forms at 
13648+. Its parsed ranges
   hold both, inherited first:
   
   ```
   [0]   32..126 -> 13648   (from ETen-B5-H, always matches first)
   [226] 32..126 -> 1       (its own, never reached)
   ```
   
   **Scope:** 31 of the 92 bundled CMaps declare mappings of their own on top 
of a `usecmap`, and all
   31 are affected. Two are horizontal (`ETenms-B5-H`, `UniJIS-UCS2-HW-H`); the 
other 29 are `-V`
   variants whose own mappings select the vertical forms, so vertical CJK gets 
horizontal glyphs.
   
   **Symptom:** the wrong glyph, and usually the wrong width with it — `/W` is 
indexed by CID, so a
   wrong CID falls outside the array and the advance drops to `/DW` = 1000. 
Latin text renders as
   `J a v a S e r v e r`.
   
   ## Fix
   
   Inherited mappings move to `inheritedCodeToCid`/`inheritedCodeToCidRanges`, 
consulted only after
   the CMap's own: own map -> own ranges -> inherited map -> inherited ranges.
   
   A `usecmap` chain stays nearest-wins, which needs opposite insertion orders: 
the maps are keyed, so
   `putAll` is last-wins (deepest first, nearer on top); the range list is 
first-match, so the nearer
   CMap's ranges go in ahead.
   
   Three things fell out of it:
   
   - **`hasCIDMappings` has to count inherited mappings.** `Identity-V` 
declares none of its own, so
     once the inherited ones move it would report false and `toCID` would 
return 0 for every code.
   - **The maps are copied, not shared.** This kills a latent aliasing bug: the 
old
     `codeToCid.putIfAbsent(length, mappings)` stored the parent's inner map 
*by reference* when the
     importing CMap had no mapping of that length yet, so a later 
`addCIDMapping` wrote into the
     cached predefined parent and corrupted it for everyone after.
   - **CID 0 is a mapping, not a miss.** The private range scan returned 0 for 
both, which with two
     range lists would send a CMap's own `cidrange` to CID 0 through to the 
inherited mappings. It
     now returns -1 for "no range covers this"; public `toCID` still returns 0.
   
   ## Tests
   
   Seven added to `TestCMapParser`, `mvn -pl fontbox -am test` green (214):
   
   | Test | Covers |
   |---|---|
   | `testUseCmapOwnMappingsWin` | the case above, both `toCID` overloads |
   | `testUseCmapChainKeepsNearestMapping` | a two-level chain stays 
nearest-wins |
   | `testUseCmapOwnMappingsBeatInheritedRanges` | own cidchar and cidrange 
beat an inherited range |
   | `testUseCmapOnlyInheritedMappings` | `Identity-V`, everything inherited |
   | `testUseCmapDoesNotShareMappingsWithTheUsedCMap` | the used CMap isn't 
mutated |
   | `testUseCmapOwnRangeBeatsInheritedChar` | own cidrange beats an inherited 
cidchar |
   | `testUseCmapOwnMappingToCidZeroIsNotAFallthrough` | CID 0 is a mapping, 
not a miss |
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to