/****************************************************************************** * ME_PointFromCharContext * * Returns a run-relative pixel position given a run-relative character * position (character offset) */ int ME_PointFromCharContext(ME_Context *c, ME_Run *pRun, int nOffset, BOOL visual_order) { SIZE size; ME_String *mask_text = NULL; WCHAR *str; if (pRun->nFlags & MERF_GRAPHICS) { if (nOffset) ME_GetOLEObjectSize(c, pRun, &size); return nOffset != 0; } else if (pRun->nFlags & MERF_ENDPARA) { nOffset = 0; } if (pRun->para->nFlags & MEPF_COMPLEX) { int x; ScriptCPtoX( nOffset, FALSE, pRun->len, pRun->num_glyphs, pRun->clusters, pRun->vis_attrs, pRun->advances, &pRun->script_analysis, &x ); if (visual_order && pRun->script_analysis.fRTL) x = pRun->nWidth - x - 1; return x; } if (c->editor->cPasswordMask) { mask_text = ME_MakeStringR(c->editor->cPasswordMask, pRun->len); str = mask_text->szData; } else str = get_text( pRun, 0 ); ME_GetTextExtent(c, str, nOffset, pRun->style, &size); ME_DestroyString( mask_text ); return size.cx; }
/****************************************************************************** * ME_GetRunSizeCommon * * Finds width, height, ascent and descent of a run, up to given character * (nLen). */ SIZE ME_GetRunSizeCommon(ME_Context *c, const ME_Paragraph *para, ME_Run *run, int nLen, int startx, int *pAscent, int *pDescent) { SIZE size; WCHAR spaceW[] = {' ',0}; nLen = min( nLen, run->len ); if (run->nFlags & MERF_ENDPARA) { nLen = min( nLen, 1 ); ME_GetTextExtent(c, spaceW, nLen, run->style, &size); } else if (para->nFlags & MEPF_COMPLEX) { size.cx = run->nWidth; } else if (c->editor->cPasswordMask) { ME_String *szMasked = ME_MakeStringR(c->editor->cPasswordMask,nLen); ME_GetTextExtent(c, szMasked->szData, nLen,run->style, &size); ME_DestroyString(szMasked); } else { ME_GetTextExtent(c, get_text( run, 0 ), nLen, run->style, &size); } *pAscent = run->style->tm.tmAscent; *pDescent = run->style->tm.tmDescent; size.cy = *pAscent + *pDescent; if (run->nFlags & MERF_TAB) { int pos = 0, i = 0, ppos, shift = 0; const PARAFORMAT2 *pFmt = ¶->fmt; if (c->editor->bEmulateVersion10 && /* v1.0 - 3.0 */ pFmt->dwMask & PFM_TABLE && pFmt->wEffects & PFE_TABLE) /* The horizontal gap shifts the tab positions to leave the gap. */ shift = pFmt->dxOffset * 2; do { if (i < pFmt->cTabCount) { /* Only one side of the horizontal gap is needed at the end of * the table row. */ if (i == pFmt->cTabCount -1) shift = shift >> 1; pos = shift + (pFmt->rgxTabs[i]&0x00FFFFFF); i++; } else { pos += lDefaultTab - (pos % lDefaultTab); } ppos = ME_twips2pointsX(c, pos); if (ppos > startx + run->pt.x) { size.cx = ppos - startx - run->pt.x; break; } } while(1);
/****************************************************************************** * ME_CharFromPointContext * * Returns a character position inside the run given a run-relative * pixel horizontal position. * * If closest is FALSE return the actual character * If closest is TRUE will round to the closest leading edge. * ie. if the second character is at pixel position 8 and third at 16 then for: * closest = FALSE cx = 0..7 return 0, cx = 8..15 return 1 * closest = TRUE cx = 0..3 return 0, cx = 4..11 return 1. */ int ME_CharFromPointContext(ME_Context *c, int cx, ME_Run *run, BOOL closest, BOOL visual_order) { ME_String *mask_text = NULL; WCHAR *str; int fit = 0; HGDIOBJ hOldFont; SIZE sz, sz2, sz3; if (!run->len || cx <= 0) return 0; if (run->nFlags & (MERF_TAB | MERF_ENDCELL)) { if (!closest || cx < run->nWidth / 2) return 0; return 1; } if (run->nFlags & MERF_GRAPHICS) { SIZE sz; ME_GetOLEObjectSize(c, run, &sz); if (!closest || cx < sz.cx / 2) return 0; return 1; } if (run->para->nFlags & MEPF_COMPLEX) { int cp, trailing; if (visual_order && run->script_analysis.fRTL) cx = run->nWidth - cx - 1; ScriptXtoCP( cx, run->len, run->num_glyphs, run->clusters, run->vis_attrs, run->advances, &run->script_analysis, &cp, &trailing ); TRACE("x %d cp %d trailing %d (run width %d) rtl %d log order %d\n", cx, cp, trailing, run->nWidth, run->script_analysis.fRTL, run->script_analysis.fLogicalOrder); return closest ? cp + trailing : cp; } if (c->editor->cPasswordMask) { mask_text = ME_MakeStringR( c->editor->cPasswordMask, run->len ); str = mask_text->szData; } else str = get_text( run, 0 ); hOldFont = ME_SelectStyleFont(c, run->style); GetTextExtentExPointW(c->hDC, str, run->len, cx, &fit, NULL, &sz); if (closest && fit != run->len) { GetTextExtentPoint32W(c->hDC, str, fit, &sz2); GetTextExtentPoint32W(c->hDC, str, fit + 1, &sz3); if (cx >= (sz2.cx+sz3.cx)/2) fit = fit + 1; } ME_DestroyString( mask_text ); ME_UnselectStyleFont(c, run->style, hOldFont); return fit; }
/****************************************************************************** * ME_PointFromCharContext * * Returns a run-relative pixel position given a run-relative character * position (character offset) */ int ME_PointFromCharContext(ME_Context *c, ME_Run *pRun, int nOffset, BOOL visual_order) { SIZE size; ME_String *mask_text = NULL; WCHAR *str; if (pRun->nFlags & MERF_GRAPHICS) { if (nOffset) ME_GetOLEObjectSize(c, pRun, &size); return nOffset != 0; } else if (pRun->nFlags & MERF_ENDPARA) { nOffset = 0; } if (c->editor->cPasswordMask) { mask_text = ME_MakeStringR(c->editor->cPasswordMask, pRun->len); str = mask_text->szData; } else str = get_text( pRun, 0 ); ME_GetTextExtent(c, str, nOffset, pRun->style, &size); ME_DestroyString( mask_text ); return size.cx; }
/****************************************************************************** * ME_GetRunSizeCommon * * Finds width, height, ascent and descent of a run, up to given character * (nLen). */ SIZE ME_GetRunSizeCommon(ME_Context *c, const ME_Paragraph *para, ME_Run *run, int nLen, int startx, int *pAscent, int *pDescent) { SIZE size; int nMaxLen = run->len; if (nLen>nMaxLen) nLen = nMaxLen; /* FIXME the following call also ensures that TEXTMETRIC structure is filled * this is wasteful for MERF_NONTEXT runs, but that shouldn't matter * in practice */ if (c->editor->cPasswordMask) { ME_String *szMasked = ME_MakeStringR(c->editor->cPasswordMask,nLen); ME_GetTextExtent(c, szMasked->szData, nLen,run->style, &size); ME_DestroyString(szMasked); } else { ME_GetTextExtent(c, get_text( run, 0 ), nLen, run->style, &size); } *pAscent = run->style->tm.tmAscent; *pDescent = run->style->tm.tmDescent; size.cy = *pAscent + *pDescent; if (run->nFlags & MERF_TAB) { int pos = 0, i = 0, ppos, shift = 0; PARAFORMAT2 *pFmt = para->pFmt; if (c->editor->bEmulateVersion10 && /* v1.0 - 3.0 */ pFmt->dwMask & PFM_TABLE && pFmt->wEffects & PFE_TABLE) /* The horizontal gap shifts the tab positions to leave the gap. */ shift = pFmt->dxOffset * 2; do { if (i < pFmt->cTabCount) { /* Only one side of the horizontal gap is needed at the end of * the table row. */ if (i == pFmt->cTabCount -1) shift = shift >> 1; pos = shift + (pFmt->rgxTabs[i]&0x00FFFFFF); i++; } else { pos += lDefaultTab - (pos % lDefaultTab); } ppos = ME_twips2pointsX(c, pos); if (ppos > startx + run->pt.x) { size.cx = ppos - startx - run->pt.x; break; } } while(1);
/****************************************************************************** * ME_CharFromPointContext * * Returns a character position inside the run given a run-relative * pixel horizontal position. * * If closest is FALSE return the actual character * If closest is TRUE will round to the closest leading edge. * ie. if the second character is at pixel position 8 and third at 16 then for: * closest = FALSE cx = 0..7 return 0, cx = 8..15 return 1 * closest = TRUE cx = 0..3 return 0, cx = 4..11 return 1. */ int ME_CharFromPointContext(ME_Context *c, int cx, ME_Run *run, BOOL closest, BOOL visual_order) { ME_String *mask_text = NULL; WCHAR *str; int fit = 0; HGDIOBJ hOldFont; SIZE sz, sz2, sz3; if (!run->len || cx <= 0) return 0; if (run->nFlags & (MERF_TAB | MERF_ENDCELL)) { if (!closest || cx < run->nWidth / 2) return 0; return 1; } if (run->nFlags & MERF_GRAPHICS) { SIZE sz; ME_GetOLEObjectSize(c, run, &sz); if (!closest || cx < sz.cx / 2) return 0; return 1; } if (c->editor->cPasswordMask) { mask_text = ME_MakeStringR( c->editor->cPasswordMask, run->len ); str = mask_text->szData; } else str = get_text( run, 0 ); hOldFont = ME_SelectStyleFont(c, run->style); GetTextExtentExPointW(c->hDC, str, run->len, cx, &fit, NULL, &sz); if (closest && fit != run->len) { GetTextExtentPoint32W(c->hDC, str, fit, &sz2); GetTextExtentPoint32W(c->hDC, str, fit + 1, &sz3); if (cx >= (sz2.cx+sz3.cx)/2) fit = fit + 1; } ME_DestroyString( mask_text ); ME_UnselectStyleFont(c, run->style, hOldFont); return fit; }
static void ME_DrawRun(ME_Context *c, int x, int y, ME_DisplayItem *rundi, ME_Paragraph *para) { ME_Run *run = &rundi->member.run; ME_DisplayItem *start = ME_FindItemBack(rundi, diStartRow); int runofs = run->nCharOfs+para->nCharOfs; int nSelFrom, nSelTo; const WCHAR wszSpace[] = {' ', 0}; if (run->nFlags & MERF_HIDDEN) return; ME_GetSelection(c->editor, &nSelFrom, &nSelTo); /* Draw selected end-of-paragraph mark */ if (run->nFlags & MERF_ENDPARA && runofs >= nSelFrom && runofs < nSelTo) ME_DrawTextWithStyle(c, x, y, wszSpace, 1, run->style, NULL, 0, 1, c->pt.y + start->member.row.nYPos, start->member.row.nHeight); /* you can always comment it out if you need visible paragraph marks */ if (run->nFlags & (MERF_ENDPARA | MERF_TAB | MERF_CELL)) return; if (run->nFlags & MERF_GRAPHICS) ME_DrawGraphics(c, x, y, run, para, (runofs >= nSelFrom) && (runofs < nSelTo)); else { if (c->editor->cPasswordMask) { ME_String *szMasked = ME_MakeStringR(c->editor->cPasswordMask,ME_StrVLen(run->strText)); ME_DrawTextWithStyle(c, x, y, szMasked->szData, ME_StrVLen(szMasked), run->style, NULL, nSelFrom-runofs,nSelTo-runofs, c->pt.y+start->member.row.nYPos, start->member.row.nHeight); ME_DestroyString(szMasked); } else ME_DrawTextWithStyle(c, x, y, run->strText->szData, ME_StrVLen(run->strText), run->style, NULL, nSelFrom-runofs,nSelTo-runofs, c->pt.y+start->member.row.nYPos, start->member.row.nHeight); } }