Dylan Smith
Email: <dylan.ah.smith AT SPAMFREE gmail DOT com>
IRC nick: DylanSmith
I started working on Wine through Google Summer of Code 2008 working on the richedit controls.
I studied at Carleton University in Canada, where I completed my Bachelors and Masters Software/Computer Engineering degrees. For my Masters research I used application-layer multicast and network coordinates to reduce the traffic cost from the presence service in the IP Multimedia Subsystem.
I am now working on Wine while looking for full-time employment as a software developer.
My development git repository is hosted at http://dylansmith.ca/git.
TO DO List
Bug 26079: Implement D3DXLoadMeshFromX
Bug 3254: Schannel decryption
Bug 5162: Windowless richedit controls
- Implement selection behaviour for richedit tables
- wordpad: Add tab and indentation markers to the ruler above the richedit control
Notes
Don't assume that all information in these notes is completely accurate, since I have failed to update it recently. I also apologize for the terse nature of these notes which may not make sense without enough knowledge about the Windows API or the Rich Text Format.
Native riched20.dll (Rich Edit v3.0) implementation of tables
The following notes are not based on the rich text format specifications, or MSDN, but instead based on observing Wine's wordpad with native riched20.dll v3.0. The Microsoft's Wordpad that I have (on XP SP3) actually uses msftedit.dll (Rich Edit v4.1) so I can't use that to test the riched20.dll.
- The border always seems to be a single pixel wide, and is always on all sides of the cell, even when no borders are specified.
- Borders should be drawn over text
- A table row requires \trowd \cellxN \intbl \row.
- \trowd clears the tab stops set by \cellxN should be at the start of the table for consistent results
\cellxN sets a tab stop for each cell in PARAFORMAT2.rgxTabs, and a table row must have at least one tabstop (i.e. PARAFORMAT2.cTabCount > 0), even if it is set with \txN
- \intbl sets the PFE_TABLE flag in PARAFORMAT2.wEffects
- \row marks the end of the table, and probably clears the PFE_TABLE flag if there are no tabstops
- Mixing \txN and \cellxN in the same table definition can result in an interesting mix of the two. For example, {\rtf\trowd\tx2900\cellx3000\cellx6000\tx6100\intbl text\row} results in a table with tab stops at 3000 at 6100. My hypothesis is that there are two seperate counts incremented for \cellxN and \txN control words, and the values are inserted directly into the rgxTabs array, so 2900 is replaced with 3000 at index 0, and 6000 is replaced with 6100 at index 1, resulting in {3000,6100}.
- \cell inserts a tab into the document at that position if there is a tabstop set with \cellxN that hasn't already been used, otherwise \cell does nothing.
- \row adds missing \cell tabs then a newline into the document at that position. Outside of a table it will still insert a newline. EM_SETPARAFORMAT cannot be used to change the tab stops for a table.
- \trgaphN sets PARAFORMAT2.dxOffset which is used as an offset before the table and before the text of each cell.
- \par inserts a space after the a \intbl marks the paragraph as a table row, but \pard clears the PFE_TABLE flag
- Backspace does not delete a cell tab, it only moves the cursor back
- Delete does not nothing just before the table, at the end of the table, or at the end of a cell
- Text cannot be added at the end of a table row. A beep is used for each typed character.
- Table rows can be deleted by selecting the entire row, which can be selected by clicking in space before the first columns text.
- Pressing enter
- at the start of the table inserts a end line before the table.
- at the start of following rows inserts a table row before the current row.
- anywhere else in a table row inserts a row after the current row.
- \pard must precede following text after a paragraph before \par is treated as an end of line instead as a space
- \intbl can be before the first \trowd as long as it is in the paragraph that will be a table row, but \trowd will reset the tab stops, so \cellxN must follow \trowd before the end of the row (i.e. before \row)
- The colour of the table border can be set with \brdrcfN but it seems to depend have some dependancies on other control words being present which I haven't tracked down.
- \brdrwN sets wBorderWidth = round(N / 10.0). Also, wBorderWidth is not used for drawing the border. wBorderWidth actually stores the width of each side (top, bottom, left, right) in one nibble.
Control Word
wBorderWidth Mask
\trbrdrt
0x000F
\trbrdrl
0x00F0
\trbrdrb
0x0F00
\trbrdrr
0xF000
- Border style control words uses the same nibble for each side as wBorderWidth does for wBorders, contrary to the documented purpose for MSDN documentation for the field.
Control Word
wBorder
\brdrdash
0
\brdrdashsm
1
\brdrdb
2
\brdrdot
3
\brdrhair
4
\brdrs
5
\brdrth
6
\brdrtriple
7
\brdrwN for each side of the cell (top, left, bottom, right) is stored in the high byte rgxTabs element for the cell. The two bits are 0 only if the \brdrwN control word is not used for the side, 1 if (0 <= N < 30), 2 if (30 <= N < 49) and 3 if (N >= 50).
Control Word
cgxTabs Mask
\clbrdrt
0x03000000
\clbrdrl
0x0C000000
\clbrdrb
0x30000000
\clbrdrr
0xC0000000
- \box sets unknown PFE_* flag on wEffects
- Native riched20.dll is quite resilient to incorrect rich text and tries to do the best it can with it.
- There is a lack of support for many control words. Open and save a rtf using native riched20.dll to remove control words that don't need to be supported.
I have found weird behaviour that I can't make sense of yet. For example, the rich text {\rtf\cellx1500\intbl text\cell\row} opened twice in a freshly opened wine wordpad will display the text as a table the first time, and not a table the second time when in Windows XP. I tried the same example using WINEDLLOVERRIDES="riched20=n" in Ubuntu, and got a different glitch where nothing is displayed even though "text" is retrieved from WM_GETTEXT, and the differences in PARAFORMAT2 is now dxOffset=3337232 and rgxTabs[0]>>24=0x7E.
Native msftedit.dll (Rich Edit v4.1) Implementation of tables
- Microsoft Wordpad uses msftedit.dll, and msftedit.dll should be available on Windows XP SP1 and up
- Tabstops are no longer used to store cell right boundaries
- Most of the values do not appear to be visible through PARAFORMAT2 data structure, except for the PFE_TABLE flag stored in wEffects.
- Cell borders are controled by the cell border control words (e.g. \clbrdrl\brdrw10\brdrs)
- Each cell side (top/left/bottom/right) of the cell can have a different border size and colour.
- Cell border types appear to all be solid (i.e. \brdrs), and these types do not appear to be saved internally, since they are all changed back to \brdrs on EM_STREAMOUT
- Table row borders (e.g. \trbrdrl\brdrs\brdrw10) control words appear to be unused, however they still seem to be stored in order to stream out.
- Nested cells are supported, and more nested cells can appear in nested cells.
- Cell text can have alignment within the cell (e.g. \qc) horizontally or vertically
- multiple paragraphs can be stored in the same cell with different paragraph formats.
- The mirrored arrow is shown where a cell can be highlighted or where a row can be highlighted.
- A row can be highlighted by clicking in the area before the first cell in the row
- A cell can be highlighted by clicking in the area before the text in the cell when it is indented.
- Rows can be deleted when they are completely highlighted
- Only cell contents are deleted when they are completely highlighted
- Rows can be added by going to the end of the row and pressing enter
- Neither cells nor rows can be deleted by using the delete or backspace key without highlighting, and the user is notified with a beep.
- Holding shift and using the left arrow will highlight
- the current row if the cursor is at the start of the row
- the cell to the left of the cursor if it is at the start of the cell, except for the first in a row
- Holding shift and using the right arrow will highlight
- the current cell if the cursor is at the end of the cell text
- the last row if the cursor is at the end of the table
- the current row and the next row if the cursor is at the end of a row, except for the last row
- Missing borders are shown with a single pixel wide border with rgb values of 192 or 0xC0 (i.e. light gray), however these borders must not be present when printing, and are also not present when
- The RTF specifications say that a table definition can appear after the cells, but this is still not supported in richedit v4.1. For example {\rtf text\cell\trowd\trgaph108\cellx2000\row} is read properly in word but not by wordpad.
Ideas for testing
- Turn the above notes into test cases by streaming in rich text using EM_STREAMIN, then checking paragraph formatting with EM_GETPARAFORMAT2.
- Manually testing would be easier if I change my dialog that dumps to contents of PARAFORMAT2 at the selection to a dialog that allow me to modify its contents using EM_SETPARAFORMAT.
- Another idea to make testing easier is to add a button to wordpad that would switch between raw and formatted rich text.
Debug patches that I already use
Let me know if any of these are of interest to you.
- richedit: print the rich text streamed from the clipboard.
- wordpad: Use SFF_SELECTION for streaming in opened files
- tests: Removed the quiet flag for running the tests
- wordpad: Enable auto URL detection.
- wordpad: Allow the richedit version to be specified
- wordpad: Show the error code when EM_STREAMIN fails.
wordpad: Show debug information with Edit->Extras menu items.
