Example #1
0
static void SetPosition(HWND hwnd)
{
	IRichEditOle* RichEditOle;
	if (SendMessage(hwnd, EM_GETOLEINTERFACE, 0, (LPARAM)&RichEditOle) == 0)
		return;

	ITextDocument* TextDocument;
	if (RichEditOle->QueryInterface(IID_ITextDocument, (void**)&TextDocument) != S_OK) {
		RichEditOle->Release();
		return;
	}

	// retrieve text range
	ITextRange* TextRange;
	if (TextDocument->Range(0, 0, &TextRange) != S_OK) {
		TextDocument->Release();
		RichEditOle->Release();
		return;
	}
	TextDocument->Release();

	int objectCount = RichEditOle->GetObjectCount();
	for (int i = objectCount - 1; i >= 0; i--) {
		REOBJECT reObj = {0};
		reObj.cbStruct  = sizeof(REOBJECT);

		HRESULT hr = RichEditOle->GetObject(i, &reObj, REO_GETOBJ_POLEOBJ);
		if (FAILED(hr)) continue;

		ISmileyBase *igsc = NULL;
		if (reObj.clsid == CLSID_NULL) 
			reObj.poleobj->QueryInterface(IID_ISmileyAddSmiley, (void**) &igsc);

		reObj.poleobj->Release();
		if (igsc == NULL) continue;

		TextRange->SetRange(reObj.cp, reObj.cp);

		BOOL res;
		POINT pt;
		RECT rect;
		hr = TextRange->GetPoint(tomStart | TA_BOTTOM | TA_LEFT, &pt.x, &pt.y);
		if (hr == S_OK) {
			res = ScreenToClient(hwnd, &pt);
			rect.bottom = pt.y;
			rect.left = pt.x;
		}
		else rect.bottom = -1;

		hr = TextRange->GetPoint(tomStart | TA_TOP | TA_LEFT, &pt.x, &pt.y);
		if (hr == S_OK) {
			res = ScreenToClient(hwnd, &pt);
			rect.top = pt.y;
			rect.left = pt.x;
		}
		else rect.top = -1;

		igsc->SetPosition(hwnd, &rect);
		igsc->Release();
	}
	TextRange->Release();
	RichEditOle->Release();
}
 static int getIndex(ITextRange range, int charIndex, Array<int> *glyphLengths = NULL) {
     // Count glyphs until pos. There is a bug in glyphRun.GetCharacterSize()
     // and glyphRun.GetContents(), so we cannot count on these.
     // They sometimes contain chars that are in the next run or contain chars
     // from the previous ones....
     // So let's do it the hard way and count only on GetSingleGlyphInRange
     // TODO: cash these results in an int table!
     // IDEA: cash it in the Story of the range, as a lookup table
     // char-index -> glyph-index
     int glyphPos = 0;
     int start = range.GetStart();
     int end = range.GetEnd();
     int size = range.GetSize();
     int scanPos = start;
     while (scanPos < charIndex) {
         // There is a way to discover ligatures: the TextRange's GetSingleGlyphInRange
         // only returns if the length is set to the amount of chars that produce a ligature
         // otherwise it fails. So we can test....
         // TODO: determine maximum ligature size.
         // Assumption is 16 for now.
         // In most cases, 1 will return a result, so there won't be too much iteration here...
         ATEGlyphID id;
         int length = 1;
         int max = MIN(16, size - scanPos);
         for (; length <= max; length++) {
             // First set the text range of the glpyhrun to test GetSingleGlyphInRange on
             range.SetRange(scanPos, scanPos + length);
             // ASCharType type = range.GetCharacterType();
             if (range.GetSingleGlyphInRange(&id)) // Found a full glyph?
                 break;
         }
         // If the length goes all the way to the end, we are likely to have encountered a hyphen glyph, as forced by the
         // AI layout engine's auto hyphenation.
         // There seems to be no way to detect this otherwise, and GetSingleGlyphInRange does not return an id
         // for the situation where the range only describes the one letter before the hyphen. So let's assume
         // this situation is only encountered for hyphens, and adjust glyphLengths, scanPos and glyphPos accordingly
         // further bellow.
         if (length < max || max == 1) {
             scanPos += length;
             // Glyph runs do not count paragraph end chars, so don't count them here either.
             if (range.GetCharacterType() != kParagraphEndChar) {
                 glyphPos++;
                 if (glyphLengths != NULL)
                     glyphLengths->add(length);
             } else if (glyphLengths != NULL) {
                 int last = glyphLengths->size() - 1;
                 if (last >= 0) {
                     int value = glyphLengths->get(last);
                     // Add length to last one. If it's negative, subtract it, since the range starts with paragraph
                     // end chars (see bellow)
                     if (value < 0) value -= length;
                     else value += length;
                     glyphLengths->set(last, value);
                 } else {
                     // Add a negative value, to indicate that range starts with paragraph end chars
                     glyphLengths->add(-length);
                 }
             }
         } else {
             // Increase glyph pos both for the actual char and the hyphen. This is guessing. There might be situations where
             // this is wrong, e.g. ligatures before hypenation, etc. TODO: Test!
             glyphPos += 2;
             scanPos++;
             if (glyphLengths != NULL) {
                 // Normal glyph (what if it's a ligature?)
                 glyphLengths->add(1);
                 // The hyphen, to be ignored as a glyph
                 glyphLengths->add(0);
             }
         }
     }
     if (scanPos > charIndex)
         glyphPos--;
     range.SetRange(start, end);
     return glyphPos;
 }