@@ -246,6 +246,8 @@ struct CompTextHost : public winrt::implements<CompTextHost, ITextHost> {
246246 // @cmember Converts screen coordinates of a specified point to the client coordinates
247247 BOOL TxScreenToClient (LPPOINT lppt) override {
248248 winrt::Windows::Foundation::Point pt{static_cast <float >(lppt->x ), static_cast <float >(lppt->y )};
249+ pt.X -= m_outer->m_contentOffsetPx .x ;
250+ pt.Y -= m_outer->m_contentOffsetPx .y ;
249251 auto localpt = m_outer->ScreenToLocal (pt);
250252 lppt->x = static_cast <LONG>(localpt.X );
251253 lppt->y = static_cast <LONG>(localpt.Y );
@@ -255,9 +257,14 @@ struct CompTextHost : public winrt::implements<CompTextHost, ITextHost> {
255257 // @cmember Converts the client coordinates of a specified point to screen coordinates
256258 BOOL TxClientToScreen (LPPOINT lppt) override {
257259 winrt::Windows::Foundation::Point pt{static_cast <float >(lppt->x ), static_cast <float >(lppt->y )};
260+
261+ if (!m_outer->m_parent ) {
262+ return false ;
263+ }
264+
258265 auto screenpt = m_outer->LocalToScreen (pt);
259- lppt->x = static_cast <LONG>(screenpt.X );
260- lppt->y = static_cast <LONG>(screenpt.Y );
266+ lppt->x = static_cast <LONG>(screenpt.X ) + m_outer-> m_contentOffsetPx . x ;
267+ lppt->y = static_cast <LONG>(screenpt.Y ) + m_outer-> m_contentOffsetPx . y ;
261268 return true ;
262269 }
263270
@@ -276,20 +283,25 @@ struct CompTextHost : public winrt::implements<CompTextHost, ITextHost> {
276283 // @cmember Retrieves the coordinates of a window's client area
277284 HRESULT TxGetClientRect (LPRECT prc) override {
278285 *prc = m_outer->getClientRect ();
286+
287+ prc->top += m_outer->m_contentOffsetPx .y ;
288+ prc->bottom += m_outer->m_contentOffsetPx .y -
289+ static_cast <LONG>(m_outer->m_layoutMetrics .contentInsets .bottom * m_outer->m_layoutMetrics .pointScaleFactor );
290+ prc->left += m_outer->m_contentOffsetPx .x ;
291+ prc->right += m_outer->m_contentOffsetPx .x -
292+ static_cast <LONG>(m_outer->m_layoutMetrics .contentInsets .right * m_outer->m_layoutMetrics .pointScaleFactor );
293+
279294 return S_OK;
280295 }
281296
282297 // @cmember Get the view rectangle relative to the inset
283298 HRESULT TxGetViewInset (LPRECT prc) override {
284299 // Inset is in HIMETRIC
285- constexpr float HmPerInchF = 2540 .0f ;
286- constexpr float PointsPerInch = 96 .0f ;
287- constexpr float dipToHm = HmPerInchF / PointsPerInch;
288300
289- prc->left = static_cast <LONG>(m_outer-> m_layoutMetrics . contentInsets . left * dipToHm) ;
290- prc->top = static_cast <LONG>(m_outer-> m_layoutMetrics . contentInsets . top * dipToHm) ;
291- prc->bottom = static_cast <LONG>(m_outer-> m_layoutMetrics . contentInsets . bottom * dipToHm) ;
292- prc->right = static_cast <LONG>(m_outer-> m_layoutMetrics . contentInsets . right * dipToHm) ;
301+ prc->left = 0 ;
302+ prc->top = 0 ;
303+ prc->bottom = 0 ;
304+ prc->right = 0 ;
293305
294306 return NOERROR;
295307 }
@@ -492,11 +504,6 @@ AutoCorrectOffCallback(LANGID langid, const WCHAR *pszBefore, WCHAR *pszAfter, L
492504facebook::react::AttributedString WindowsTextInputComponentView::getAttributedString () const {
493505 // Use BaseTextShadowNode to get attributed string from children
494506
495- auto childTextAttributes = facebook::react::TextAttributes::defaultTextAttributes ();
496- childTextAttributes.fontSizeMultiplier = m_fontSizeMultiplier;
497-
498- childTextAttributes.apply (windowsTextInputProps ().textAttributes );
499-
500507 auto attributedString = facebook::react::AttributedString{};
501508 // auto attachments = facebook::react::BaseTextShadowNode::Attachments{};
502509
@@ -1114,6 +1121,9 @@ void WindowsTextInputComponentView::updateProps(
11141121 !facebook::react::floatEquality (
11151122 oldTextInputProps.textAttributes .letterSpacing , newTextInputProps.textAttributes .letterSpacing ) ||
11161123 oldTextInputProps.textAttributes .fontFamily != newTextInputProps.textAttributes .fontFamily ||
1124+ oldTextInputProps.textAttributes .fontStyle != newTextInputProps.textAttributes .fontStyle ||
1125+ oldTextInputProps.textAttributes .textDecorationLineType !=
1126+ newTextInputProps.textAttributes .textDecorationLineType ||
11171127 !facebook::react::floatEquality (
11181128 oldTextInputProps.textAttributes .maxFontSizeMultiplier ,
11191129 newTextInputProps.textAttributes .maxFontSizeMultiplier )) {
@@ -1129,6 +1139,7 @@ void WindowsTextInputComponentView::updateProps(
11291139 }
11301140
11311141 if (oldTextInputProps.multiline != newTextInputProps.multiline ) {
1142+ m_recalculateContentVerticalOffset = true ;
11321143 m_multiline = newTextInputProps.multiline ;
11331144 m_propBitsMask |= TXTBIT_MULTILINE | TXTBIT_WORDWRAP;
11341145 if (newTextInputProps.multiline ) {
@@ -1278,6 +1289,10 @@ void WindowsTextInputComponentView::updateLayoutMetrics(
12781289 unsigned int newWidth = static_cast <unsigned int >(layoutMetrics.frame .size .width * layoutMetrics.pointScaleFactor );
12791290 unsigned int newHeight = static_cast <unsigned int >(layoutMetrics.frame .size .height * layoutMetrics.pointScaleFactor );
12801291
1292+ if (newHeight != m_imgHeight || oldLayoutMetrics.pointScaleFactor != layoutMetrics.pointScaleFactor ) {
1293+ m_recalculateContentVerticalOffset = true ;
1294+ }
1295+
12811296 if (newWidth != m_imgWidth || newHeight != m_imgHeight) {
12821297 m_drawingSurface = nullptr ; // Invalidate surface if we get a size change
12831298 }
@@ -1416,6 +1431,8 @@ void WindowsTextInputComponentView::FinalizeUpdates(
14161431
14171432void WindowsTextInputComponentView::UpdatePropertyBits () noexcept {
14181433 if (m_propBitsMask != 0 ) {
1434+ if ((m_propBits & TXTBIT_CHARFORMATCHANGE) == TXTBIT_CHARFORMATCHANGE)
1435+ m_recalculateContentVerticalOffset = true ;
14191436 DrawBlock db (*this );
14201437 winrt::check_hresult (m_textServices->OnTxPropertyBitsChange (m_propBitsMask, m_propBits));
14211438 m_propBitsMask = 0 ;
@@ -1427,6 +1444,10 @@ void WindowsTextInputComponentView::InternalFinalize() noexcept {
14271444 if (m_mounted) {
14281445 UpdatePropertyBits ();
14291446
1447+ if (m_recalculateContentVerticalOffset) {
1448+ calculateContentVerticalOffset ();
1449+ }
1450+
14301451 ensureDrawingSurface ();
14311452 if (m_needsRedraw) {
14321453 DrawText ();
@@ -1488,12 +1509,6 @@ void WindowsTextInputComponentView::UpdateCharFormat() noexcept {
14881509 // m_crText = RemoveAlpha(fontDetails.FontColor);
14891510 // }
14901511
1491- // set font face
1492- // cfNew.dwMask |= CFM_FACE;
1493- // NetUIWzCchCopy(cfNew.szFaceName, _countof(cfNew.szFaceName), fontDetails.FontName.c_str());
1494- // cfNew.bPitchAndFamily = FF_DONTCARE;
1495-
1496- // set font size -- 15 to convert twips to pt
14971512 const auto &props = windowsTextInputProps ();
14981513 float fontSize =
14991514 (std::isnan (props.textAttributes .fontSize ) ? facebook::react::TextAttributes::defaultTextAttributes ().fontSize
@@ -1504,8 +1519,8 @@ void WindowsTextInputComponentView::UpdateCharFormat() noexcept {
15041519 fontSize *=
15051520 (maxFontSizeMultiplier >= 1 .0f ) ? std::min (maxFontSizeMultiplier, m_fontSizeMultiplier) : m_fontSizeMultiplier;
15061521
1507- // TODO get fontSize from props.textAttributes, or defaultTextAttributes, or fragment?
15081522 cfNew.dwMask |= CFM_SIZE;
1523+ // set font size -- 15 to convert twips to pt
15091524 cfNew.yHeight = static_cast <LONG>(fontSize * 15 );
15101525
15111526 // set bold
@@ -1540,7 +1555,11 @@ void WindowsTextInputComponentView::UpdateCharFormat() noexcept {
15401555 std::wstring fontFamily =
15411556 std::wstring (props.textAttributes .fontFamily .begin (), props.textAttributes .fontFamily .end ());
15421557 wcsncpy_s (cfNew.szFaceName , fontFamily.c_str (), LF_FACESIZE);
1558+ } else {
1559+ cfNew.dwMask |= CFM_FACE;
1560+ wcsncpy_s (cfNew.szFaceName , L" Segoe UI\0 " , LF_FACESIZE);
15431561 }
1562+ cfNew.bPitchAndFamily = FF_DONTCARE;
15441563
15451564 // set char offset
15461565 cfNew.dwMask |= CFM_OFFSET;
@@ -1549,7 +1568,8 @@ void WindowsTextInputComponentView::UpdateCharFormat() noexcept {
15491568 // set letter spacing
15501569 float letterSpacing = props.textAttributes .letterSpacing ;
15511570 if (!std::isnan (letterSpacing)) {
1552- updateLetterSpacing (letterSpacing);
1571+ cfNew.dwMask |= CFM_SPACING;
1572+ cfNew.sSpacing = static_cast <SHORT>(letterSpacing * 20 ); // Convert to TWIPS
15531573 }
15541574
15551575 // set charset
@@ -1665,7 +1685,7 @@ winrt::com_ptr<::IDWriteTextLayout> WindowsTextInputComponentView::CreatePlaceho
16651685 const auto &props = windowsTextInputProps ();
16661686 facebook::react::TextAttributes textAttributes = props.textAttributes ;
16671687 if (std::isnan (props.textAttributes .fontSize )) {
1668- textAttributes .fontSize = 12 . 0f ;
1688+ facebook::react::TextAttributes::defaultTextAttributes () .fontSize ;
16691689 }
16701690 textAttributes.fontSizeMultiplier = m_fontSizeMultiplier;
16711691 fragment1.string = props.placeholder ;
@@ -1682,6 +1702,26 @@ winrt::com_ptr<::IDWriteTextLayout> WindowsTextInputComponentView::CreatePlaceho
16821702 return textLayout;
16831703}
16841704
1705+ void WindowsTextInputComponentView::calculateContentVerticalOffset () noexcept {
1706+ m_recalculateContentVerticalOffset = false ;
1707+
1708+ const auto &props = windowsTextInputProps ();
1709+
1710+ m_contentOffsetPx = {
1711+ static_cast <LONG>(m_layoutMetrics.contentInsets .left * m_layoutMetrics.pointScaleFactor ),
1712+ static_cast <LONG>(m_layoutMetrics.contentInsets .top * m_layoutMetrics.pointScaleFactor )};
1713+
1714+ if (props.multiline ) {
1715+ // Align to the top for multiline
1716+ return ;
1717+ }
1718+
1719+ auto [contentWidth, contentHeight] = GetContentSize ();
1720+
1721+ m_contentOffsetPx.y += static_cast <LONG>(std::round (
1722+ ((m_layoutMetrics.getContentFrame ().size .height - contentHeight) / 2 ) * m_layoutMetrics.pointScaleFactor ));
1723+ }
1724+
16851725void WindowsTextInputComponentView::DrawText () noexcept {
16861726 m_needsRedraw = true ;
16871727 if (m_cDrawBlock || theme ()->IsEmpty () || !m_textServices) {
@@ -1707,16 +1747,13 @@ void WindowsTextInputComponentView::DrawText() noexcept {
17071747 assert (d2dDeviceContext->GetUnitMode () == D2D1_UNIT_MODE_DIPS);
17081748
17091749 RECTL rc{
1710- static_cast <LONG>( offset.x ) ,
1711- static_cast <LONG>( offset.y ) ,
1712- static_cast <LONG>( offset.x ) + static_cast <LONG>(m_imgWidth),
1713- static_cast <LONG>( offset.y ) + static_cast <LONG>(m_imgHeight)};
1750+ offset.x + m_contentOffsetPx. x ,
1751+ offset.y + m_contentOffsetPx. y ,
1752+ offset.x + m_contentOffsetPx. x + static_cast <LONG>(m_imgWidth),
1753+ offset.y + m_contentOffsetPx. y + static_cast <LONG>(m_imgHeight)};
17141754
17151755 RECT rcClient{
1716- static_cast <LONG>(offset.x ),
1717- static_cast <LONG>(offset.y ),
1718- static_cast <LONG>(offset.x ) + static_cast <LONG>(m_imgWidth),
1719- static_cast <LONG>(offset.y ) + static_cast <LONG>(m_imgHeight)};
1756+ offset.x , offset.y , offset.x + static_cast <LONG>(m_imgWidth), offset.y + static_cast <LONG>(m_imgHeight)};
17201757
17211758 {
17221759 m_cDrawBlock++; // Dont use AutoDrawBlock as we are already in draw, and dont need to draw again.
@@ -1771,8 +1808,8 @@ void WindowsTextInputComponentView::DrawText() noexcept {
17711808 // draw text
17721809 d2dDeviceContext->DrawTextLayout (
17731810 D2D1::Point2F (
1774- static_cast <FLOAT>(( offset.x + m_layoutMetrics. contentInsets . left ) / m_layoutMetrics.pointScaleFactor ) ,
1775- static_cast <FLOAT>(( offset.y + m_layoutMetrics. contentInsets . top ) / m_layoutMetrics.pointScaleFactor ) ),
1811+ static_cast <FLOAT>(offset.x + m_contentOffsetPx. x ) / m_layoutMetrics.pointScaleFactor ,
1812+ static_cast <FLOAT>(offset.y + m_contentOffsetPx. y ) / m_layoutMetrics.pointScaleFactor ),
17761813 textLayout.get (),
17771814 brush.get (),
17781815 D2D1_DRAW_TEXT_OPTIONS_ENABLE_COLOR_FONT);
@@ -1848,22 +1885,6 @@ void WindowsTextInputComponentView::autoCapitalizeOnUpdateProps(
18481885 }
18491886}
18501887
1851- void WindowsTextInputComponentView::updateLetterSpacing (float letterSpacing) noexcept {
1852- CHARFORMAT2W cf = {};
1853- cf.cbSize = sizeof (CHARFORMAT2W);
1854- cf.dwMask = CFM_SPACING;
1855- cf.sSpacing = static_cast <SHORT>(letterSpacing * 20 ); // Convert to TWIPS
1856-
1857- LRESULT res;
1858-
1859- // Apply to all existing text like placeholder
1860- winrt::check_hresult (m_textServices->TxSendMessage (EM_SETCHARFORMAT, SCF_ALL, reinterpret_cast <LPARAM>(&cf), &res));
1861-
1862- // Apply to future text input
1863- winrt::check_hresult (
1864- m_textServices->TxSendMessage (EM_SETCHARFORMAT, SCF_SELECTION, reinterpret_cast <LPARAM>(&cf), &res));
1865- }
1866-
18671888void WindowsTextInputComponentView::updateAutoCorrect (bool enable) noexcept {
18681889 LRESULT lresult;
18691890 winrt::check_hresult (m_textServices->TxSendMessage (
0 commit comments