Matterhorn 31-007 · PDF/UA-1 UA1:7.21.3.3-1
CMap WMode differs between dictionary and CMap program
Writing mode (horizontal or vertical) must be declared consistently in the dictionary and the stream.
The condition, as the protocol states it. “The WMode entry in a CMap dictionary is not identical to the WMode value in the CMap stream.”
Matterhorn Protocol 1.1, checkpoint 31, index 31-007, section UA1:7.21.3.3-1. Software can decide this one on its own.
What a screen reader actually does
Text direction may be misinterpreted.
One setting, written twice
An embedded CMap is a stream. The stream’s data is a CMap program in the PostScript-derived syntax Adobe defined for CMap resources; the stream’s dictionary is ordinary PDF. Both can state the writing mode:
14 0 obj
<< /Type /CMap
/CMapName /Custom-V
/CIDSystemInfo << /Registry (Adobe) /Ordering (Japan1) /Supplement 6 >>
/WMode 1 % the dictionary says vertical
/Length 1934 >>
stream
%!PS-Adobe-3.0 Resource-CMap
/CIDInit /ProcSet findresource begin
12 dict begin
begincmap
/CMapName /Custom-V def
/WMode 0 def % the program says horizontal
...
endcmap
endstream
0 is horizontal, 1 is vertical. In ISO 32000-1 the dictionary entry is optional and defaults to 0, as does the program’s. PDF/UA-1 requires that, where the CMap is embedded, the integer in the dictionary be identical to the value in the stream. The example above fails.
What writing mode changes
Writing mode decides which way the text advances. In horizontal mode each glyph moves the pen to the right by its width from the font’s /W array. In vertical mode it moves the pen down, using the separate vertical metrics in /W2 and /DW2, and glyphs are positioned on a vertical origin. A vertical CMap may also map a handful of codes — brackets, the long-vowel mark, some punctuation — to the vertical forms of those glyphs.
So a viewer that believes the dictionary sets the run above as a column; one that believes the program sets it as a row. The characters are the same and in the same order. Their positions are not: a column of text drawn as a row runs off the edge of its box or over its neighbours, and a row drawn as a column becomes a narrow stack.
What the reader gets
The words do not change. WMode does not alter which CID a code maps to, so the characters a screen reader receives, and their order through the structure tree, are the same in either mode. This is why the condition’s effect on speech is easy to overstate.
Its effect on everything else is not. A low-vision user magnifying the page sees whichever layout their viewer chose, which may overprint. Text selection, copy and paste, find, and any reflow view rebuild lines from glyph positions, and they rebuild different lines from different positions — so the same document can copy as one string in one viewer and in a different order in another. And untagged or partly tagged content, which a screen reader reads by position, inherits that disagreement directly.
Where it comes from
From producers that write the stream dictionary and the CMap program separately. A writer that fills in the dictionary from a template — /WMode 0 every time — and copies a vertical CMap program in from a resource file will produce this for every vertical font it embeds. So will one that derives a -V CMap from a -H one and updates the dictionary but not the program, or the reverse.
How to check it free
qpdf. Find the Type 0 font’s object number with pdffonts (an embedded CMap shows Custom in its encoding column), print the font with qpdf file.pdf --show-object=12, and follow /Encoding to the CMap. qpdf file.pdf --show-object=14 shows the dictionary’s /WMode; adding --filtered-stream-data prints the program, where you are looking for /WMode n def.
veraPDF with its PDF/UA-1 profile tests it under clause 7.21.3.3.
Acrobat Pro shows the stream dictionary in Preflight: All tools → Use print production → Preflight, then Options → Browse Internal PDF Structure, and open the font’s Encoding from the page’s Resources. Per Adobe’s documentation this window is for inspection; it does not edit.
How to fix it
Acrobat has no command that edits a CMap. Re-exporting from the source is the clean fix; Adobe’s guidance on character-encoding problems also points to re-creating the PDF.
If you edit the file instead, first decide which value is true. The source document is the authority: text set vertically in the original wants 1. The CMap’s own name is a strong hint — a -V suffix means vertical by convention — and so is the font: a CIDFont with explicit /W2 vertical metrics was prepared for vertical setting. Then make the other side agree. The dictionary is the easier side to change: qpdf --json-output with --json-object writes the CMap object out, you change "/WMode", and --update-from-json applies it. Render the result against the original before keeping it.
What Taggart does
For each Type 0 font that text is set in and whose CMap is embedded, Taggart reads /WMode from the stream dictionary and the first /WMode value in the CMap program, and reports a blocker when both are present and differ:
/ABCDEF+JPMincho-Regular: the CMap dictionary declares /WMode 1 but the CMap stream declares 0.
The finding carries both values, the font’s object number and the first page it appears on.
It only compares when both sides state a value. A dictionary with no /WMode over a program that says 1 is not reported, even though the dictionary’s default is 0 and a strict reading would call that a difference; nor is the reverse. If you are checking a vertical document by hand, look for that case too.
There is no fix in Taggart. The finding stays a blocker until the file is re-made or edited, and Taggart will not write the PDF/UA identifier while it stands.
How Taggart handles it
Taggart checks for this condition automatically and reports it as a blocker, with where in the file it found it.
Whatever Taggart changes, the page still looks identical. Fixes edit the PDF object model, not the content streams, and every remediation is re-rendered and compared against the original at structural similarity ≥ 0.999 before you get the file back. A tool that quietly reflows your document is worse than no tool.
Frequently asked questions
What is WMode?
The writing mode a CMap selects for the font it is used with: 0 for horizontal, 1 for vertical. The -H and -V pairs of predefined CMaps — UniJIS-UTF16-H and UniJIS-UTF16-V — differ chiefly in this, plus a few codes that map to vertical glyph forms in the -V version.
Why is it written in two places?
Because an embedded CMap is a PDF stream wrapped around a PostScript-style CMap program. The program sets /WMode itself, and ISO 32000-1 also gives the stream dictionary a /WMode entry. PDF/UA requires the two to be identical so that no viewer has to choose.
Does a screen reader read vertical text differently?
No. A screen reader reads characters in the order the content and the structure tree give them, and WMode does not change which characters a code maps to. What WMode changes is where each glyph is placed — down the page or across it — and that matters to people reading the page by eye and to any tool that rebuilds text from glyph positions.
Does this apply to predefined CMaps like UniJIS-UTF16-V?
No. A predefined CMap is named, not embedded, so there is no stream dictionary to disagree with it. The condition only exists for embedded CMaps.
Where this sits in the standards
| Standard | Reference |
|---|---|
| Matterhorn Protocol 1.1 | Checkpoint 31 (Fonts), index 31-007 |
| PDF/UA-1 (ISO 14289-1) | Clause 7.21.3.3-1 |
| WCAG 2.1 | 1.3.1 Info and Relationships — Level A |
| EN 301 549 / Section 508 / ADA Title II | All three point at WCAG 2.1 Level AA for non-web documents, so a Level A or AA criterion here is in scope for each of them. |
Related conditions
- 31-006 A CMap is neither listed in ISO 32000-1 Table 118 nor embeddedA predefined CMap must be one of the standard names; anything else must be embedded in the file.
- 31-008 A CMap references another CMap which is not listed in ISO 32000-1 Table 118A UseCMap chain must terminate at a predefined CMap.
- 31-002 CIDSystemInfo Ordering values are not identicalThe CMap and the descendant CID font must agree on the character collection ordering.
Other conditions in checkpoint 31
Checkpoint 31 covers fonts. These are its other failure conditions; the ones without a link are in the rule set but do not have a written page yet.
- 31-001 CIDSystemInfo Registry values are not identicalThe CMap and the descendant CID font must agree on the character collection registry.
- 31-002 CIDSystemInfo Ordering values are not identicalThe CMap and the descendant CID font must agree on the character collection ordering.
- 31-003 CIDSystemInfo Supplement of the CID font is lower than that of the CMapThe font's character collection supplement must be at least as new as the CMap's, or the CMap may reference CIDs the font does not define.
- 31-004 A Type 2 CID font contains neither a stream nor the name Identity as CIDToGIDMapCIDToGIDMap must be either the name /Identity or a stream mapping CIDs to glyph indices.
- 31-005 A Type 2 CID font does not contain a CIDToGIDMap entryThe entry is absent entirely.
- 31-006 A CMap is neither listed in ISO 32000-1 Table 118 nor embeddedA predefined CMap must be one of the standard names; anything else must be embedded in the file.
- 31-008 A CMap references another CMap which is not listed in ISO 32000-1 Table 118A UseCMap chain must terminate at a predefined CMap.
- 31-009 For a font used by text intended to be rendered the font program is not embeddedPDF/UA-1 requires every font used for visible text to be embedded, so the document renders and extracts identically everywhere. A glyph counts as rendered if the text render mode is not 3.
- 31-010 A font program is embedded that is not legally embeddable for unlimited, universal renderingThe font's embedding permission bits forbid the kind of embedding used. Machines can read the flags but the flags may not reflect the actual licence.
- 31-011 The embedded font program does not contain glyphs for all referenced glyphsThe subset embedded in the file is missing glyphs the content stream asks for — very common when a document is edited after subsetting.
- 31-012 A glyph present in an embedded Type 1 font program is not listed in CharSetCharSet must accurately list the glyphs in the embedded subset.
- 31-013 A glyph listed in CharSet is not present in the Type 1 font programCharSet promises glyphs the font does not contain.
- 31-014 A glyph present in an embedded CID font program is not listed in CIDSetCIDSet must accurately list the CIDs in the embedded subset.
- 31-015 A glyph listed in CIDSet is not present in the CID font programCIDSet promises CIDs the font does not contain.
- 31-016 Glyph widths in the font dictionary and the font program differThe /Widths array must agree with the embedded font program.
- 31-017 A non-symbolic TrueType font has no non-symbolic cmapA font declared non-symbolic must actually carry a (3,1) or (1,0) cmap subtable.
- 31-018 A glyph cannot be looked up by any non-symbolic cmap entrySome rendered glyph is unreachable through the declared cmap tables.
- 31-019 The font dictionary for a non-symbolic TrueType font does not contain an Encoding entryNon-symbolic TrueType fonts must declare an /Encoding.
- 31-020 The Encoding dictionary for a non-symbolic TrueType font does not contain BaseEncodingIf /Encoding is a dictionary it must name a /BaseEncoding.
- 31-021 BaseEncoding is neither MacRomanEncoding nor WinAnsiEncodingOnly MacRomanEncoding and WinAnsiEncoding are permitted for non-symbolic TrueType fonts.
- 31-022 Differences contains glyph names not listed in the Adobe Glyph ListGlyph names in /Differences must be resolvable through the Adobe Glyph List so a processor can derive Unicode.
- 31-023 Differences present but the font has no (3,1) Microsoft Unicode cmapThe Differences array is resolved through the (3,1) cmap; without it the mapping is undefined.
- 31-024 The Encoding entry is present in the font dictionary for a symbolic TrueType fontSymbolic TrueType fonts must not carry an /Encoding; the font's own cmap governs.
- 31-025 The embedded font program for a symbolic TrueType font contains no cmapA symbolic TrueType font must contain at least one cmap subtable.
- 31-026 A symbolic TrueType font has multiple cmaps but none is a (3,0) Microsoft Symbol cmapWith multiple cmaps present, a (3,0) symbol cmap is required to disambiguate.
- 31-027 A font dictionary does not contain the ToUnicode entry and no exemption appliesA ToUnicode CMap is required unless the font uses MacRoman/MacExpert/WinAnsi encoding, or is a Type 1/Type 3 whose glyph names are all in the Adobe Glyph List or the Symbol set, or is a Type 0 whose descendant uses a standard Adobe character collection, or is a non-symbolic TrueType.
- 31-028 Unicode values in the ToUnicode CMap are zeroU+0000 is not a valid mapping target; it usually means the producer could not determine the character and wrote a placeholder.
- 31-029 Unicode values in the ToUnicode CMap are U+FEFF or U+FFFEByte-order marks are not characters and must not appear as mapping targets.
- 31-030 Characters used in text showing operators reference the .notdef glyphThe content stream paints glyph index 0, which is by definition "no glyph" — typically a hollow box or nothing at all.
Check your own file. Taggart’s validator is free and unlimited — 75 of the 87 Matterhorn conditions software can decide, with the other 12 listed for you to confirm; no watermark, no expiry, and no account needed up to 60 pages.
Checked with Taggart on a generated file that fails this condition on . The Acrobat steps follow Adobe’s documentation and were not walked through by hand. Last updated .