In order to make the message handling available to windowless richedit
controls, the message handling must be in a function that can be
called from the ITextServices_TxSendMessage method. This method will
never have a handle to a window to pass to RichEditWndProc_common in
order to get the editor with GetWindowLongPtrW, but passing the editor
will work (even if hWnd is NULL).
When the text is wrapped, the positions for all the runs, paragraphs,
and cells are already calculated and stored. The only thing left to do
for painting is to offset them by the formatting rectangle and the
scroll position.
During wrapping there were three different heights that were being
stored, with only one of them being done correctly. The other ones
failed to incorporate the height of the paragraph or row, so ended up
being incorrect.
The formatting rectangle is set with EM_SETRECT, and retrieved with
EM_GETRECT, so it corresponds to rcFormat in the code. This defines the
area that the richedit control should draw the text so that it is
offset by the top-left corner of the formatting rectangle, and clipped
so that it doesn't draw past the bottom or right hand side. Thus this
is important for implementing windowless richedit controls to not
interfere with the rest of the window.
There were several methods that do not have a HRESULT for a return
value, so returning E_NOTIMPL is not appropriate. For all the BOOL
return values FALSE was returned to indicate the operation was not
performed.
The RichEditWndProc_common function is big enough already by handling
all the window messages, so moving code to handle a message to its own
function makes the code more readable.
There is no reason for the rich text format parser to need a handle to
the window, and even if there were it has a handle to the editor which
contains a handle to the window. It is better to remove this
considering we need to cut down on the use of window handles to
implement windowless richedit controls.
The vertical scrollbar state is stored internally within the control,
so should be used when possible. This will become more necessary when
windowless richedit controls are implemented, and there will no hWnd
to pass to GetScrollInfo.
Comparing the editor as apposed to the handle to the window will work
just as well right now, but will also work when there is no window
handle to make a comparison with, which will be the case with
windowless richedit controls.
The code for the ME_EnsureVisible function does exactly what
EM_SCROLLCARET does, yet this code is duplicated in order to handle
this message. It is simpler to just use the existing function to
implement the message, and avoid internally sending the EM_SCROLLCARET
when this function is available.
EditWordBreakProc documented the third parameter as being the number
of unicode characters in the string for richedit 2.0 and up. It turns
out that it should actually be the number of bytes in the string.
For some reason EM_POSFROMCHAR was returning 0 when the position was
equal to the end of the text, or beyond the end of the text. Instead
it should use the position at the end of the text for both these
cases. The x value was also seen to be offset by 1 according to the
tests.
Previously the shortcuts for cut, copy, paste, undo, redo, and select
all were being handled during the WM_CHAR message. These tests show
that these shortcuts should be handled with the WM_KEYDOWN message
instead.
There were some notifications that weren't sent in ME_UpdateRepaint
while redraw was disabled, so this verifies that they are not sent
with redraw disabled.
The assertion was not valid, because it neglected to take into account
the situation where a line break is forced with a MERF_ENDROW run
(caused by \line control word or pressing Shift-Enter). This means
that spaces can cause a line wrap after a forced line break as well as
after a paragraph break, so we cannot assert that it is the first row
in the paragraph.
The test for EM_GETLINE was testing to make sure the null terminating
character was written at the end of the text as long as the buffer was
long enough, and also tested to make sure that no other bytes were
written after this null terminating character. This is consistent with
Windows 2000 and up, but not for previous versions of Windows.
The table properties are streamed out at the start of the table for
non-nested tables, and at the end of the table for nested tables. The
assertion caught the fact that I didn't get the start of the table row
for nested tables before trying to stream out the properties.
The call to ME_GetTableRowStart will handle both of these cases by
getting the table row start paragraph and asserting that it is found.
This call was also the reason for removing the const qualifier on one
of the parameters.
Previously the paragraph and cell border properties were lost when
deleting the text, then undoing the deletion. This would cause tables
to lose the colour and width of the table border.
Previously the control words in skipped groups were being processed by
the read hook on the RTF parser. By moving this code into the class
callbacks for the parser, the skipped groups actually remain skipped.
For simple tables cells are represented with tabs, and a table row is
ended at the end of the paragraph, so native richedit controls
substitute spaces for \tab and \par rich text format control words.
The values returned by EM_SETPARAFORMAT and EM_GETPARAFORMAT previously
indicated an error, and the included tests shows that Windows behaves as
documented.
After selection a word, line, or paragraph with multi click selection or using
the selection bar, then shift can be held and the arrows can be used to move
one of the ends of the selection.
The problem was that the paragraph format was being retrieved,
slightly modified and then used to set the paragraph format, without
limiting the mask to what was being set. The PFM_OFFSETINDENT mask flag
being valid meant that dxStartIndent specifies a relative offset, thus
dxStartIndent was doubled.
This is a minimal model of what happens in Corman Lisp 3.0 -
subclassed window class that unconditionally calls ShowScrollBar() to
force scrollbar visibility.
Some applications have never heard of ES_DISABLENOSCROLL and attempt
to force scrollbars to be always shown (with ShowScrollBar() or
similar) when otherwise richedit would hide them. If richedit attempts
to wrestle control back, a recursive loop of requests can result if
app overrides WM_SIZE behavior. Apparently native never reads the
scrollbar state, and operates from some sort of internal state, so
that scrollbars can be modified externally without native trying to
wrestle back control. This is confirmed by attached tests. An
exception: EM_SCROLL will restore visibility to a scrollbar that was
forcibly hidden.
EM_AUTOURLDETECT tests are taking too much time, so this patch tests
just one URL and one non-URL for all messages but WM_SETTEXT. Also,
remove one trace that spams the output needlessly.
This also reverts commit 2b52dd845097f16076c0185b02a003f63898dcab:
wordpad: Empty the richedit undo buffer on creation.
The reverted commit I created to fix an issue that only applied to Wine,
but it just masked the issue which was in richedit controls. The
default character format was set in two places while wordpad was
starting up, and caused wordpad to have two undo items at startup.
Trying to set the font size to a value larger than 1638
in points (yHeightCharPtsMost) using EM_SETCHARFORMAT will cause it to be
set to actually set to the maximum.
In version 1.0 of the richedit controls highlighting is done by
inverting the colours. Version 2.0 and up highlight instead draw
the text using system colours for the background and the text.
The uncommon case that this patch handles is enough whitespace being
on the first line of a paragraph to cause it to wrap. In this case the
first non-space character will be wrapped onto the next line.
When the cursor is moved over the selection bar, without holding any
mouse buttons down, the cursor would be repeatably set between the
normal cursor, set by DefWindowProc for the WM_SETCURSOR message, and
the reversed cursor, set by ME_MouseMove.
I created a function to set the default paragraph format to ensure
consistency when this is done. This initial paragraph format is also
now more consistent with native richedit controls. The dwMask value
always appears to have the same value when retrieved from the native
richedit controls, so all the mask values are now initialized when the
PARAFORMAT2 structure is created.
The PARAFORMAT structure has a bit in wEffects to indicate whether the
paragraph is a table or not, so this should be used instead of a private
bTable value, since this structure can be retrieved with EM_GETPARAFORMAT.
The cursor should only be shown when there is no selection, since this
is how it is done in Windows. This patch avoids showing the cursor when
there is a selection, and destroys the cursor when a selection is made.