Example #1
0
/*----------------------------------------------------------------------------------------------
	Copy cb bytes from the current position in this stream to the current position in
	the stream *pstm.
	Uses FileStream ${#Read} and ${#Write} methods. Note that though it would be more efficient
	in some	cases to bypass the Read method for several consecutive reads, the case of copying
	to a clone would require special handling.
	There is no check for overlapping read & write areas. REVIEW (JohnL): Should there be?
----------------------------------------------------------------------------------------------*/
STDMETHODIMP FileStream::CopyTo(IStream * pstm, ULARGE_INTEGER cb, ULARGE_INTEGER * pcbRead,
	ULARGE_INTEGER * pcbWritten)
{
	BEGIN_COM_METHOD;
	ChkComArgPtr(pstm);
	ChkComArgPtrN(pcbRead);
	ChkComArgPtrN(pcbWritten);

	if (cb.HighPart)
		ThrowHr(WarnHr(STG_E_INVALIDPARAMETER)); // handle only 32-bit byte counts
	// REVIEW JohnL: should we nevertheless handle cb == max ULARGE_INTEGER as a special case?
	if (pstm == this)
		ThrowHr(WarnHr(STG_E_INVALIDPARAMETER)); // prevent copy to self
	// REVIEW JohnL: is this correct?

	if (pcbRead)
		(*pcbRead).QuadPart = 0;
	if (pcbWritten)
		(*pcbWritten).QuadPart = 0;

	const ULONG kcbBufferSize = 4096;
	ULONG cbReadTotal;
	ULONG cbWrittenTotal = 0;
	byte prgbBuffer[kcbBufferSize];
	ULONG cbRead = 0;
	ULONG cbWritten;
	ULONG cbr = 0;

	for (cbReadTotal = 0; (cbReadTotal < cb.LowPart) && (cbRead == cbr); )
	{
		cbr = cb.LowPart - cbReadTotal;
		if (cbr > kcbBufferSize)
			cbr = kcbBufferSize;
		CheckHr(Read((void *)prgbBuffer, cbr, &cbRead));
		cbReadTotal += cbRead;
		if (cbRead)
		{
			CheckHr(pstm->Write((void *)prgbBuffer, cbRead, &cbWritten));
			cbWrittenTotal += cbWritten;
		}
	}
	if (pcbRead)
		(*pcbRead).LowPart = cbReadTotal;
	if (pcbWritten)
		(*pcbWritten).LowPart = cbWrittenTotal;

	// REVIEW JohnL: How do we define "success" for CopyTo? Should we return a failure if
	//                 cbWrittenTotal != cbReadTotal?
	END_COM_METHOD(g_fact, IID_IStream);
}
Example #2
0
/*----------------------------------------------------------------------------------------------
	Retrieves a specified number of items in the enumeration sequence.

	Retrieves the next celt items in the enumeration sequence. If there are fewer than the
	requested number of elements left in the sequence, it retrieves the remaining elements.
	The number of elements actually retrieved is returned through pceltFetched (unless the
	caller passed in NULL for that parameter).

	This is a standard COM IEnumFORMATETC method.

	@param celt Desired number of elements to retrieve.
	@param rgelt Pointer to an array for returning the retrieved elements.
	@param pceltFetched Pointer to a count of the number of elements actually retrieved, or
					NULL.

	@return S_OK (if celt items retrieved), S_FALSE (if fewer than celt items retrieved), or
					E_POINTER.
----------------------------------------------------------------------------------------------*/
STDMETHODIMP LgTsEnumFORMATETC::Next(ULONG celt, FORMATETC * rgelt, ULONG * pceltFetched)
{
	BEGIN_COM_METHOD;
	ChkComArrayArg(rgelt, celt);
	ChkComArgPtrN(pceltFetched);

	if (celt == 0)
	{
		if (pceltFetched)
			*pceltFetched = 0;
		return S_OK;
	}
	int cfmteAvail = kcfmteLim - m_ifmte;
	if (cfmteAvail <= 0)
	{
		if (pceltFetched)
			*pceltFetched = 0;
		return S_FALSE;
	}
	int cfmte;
	if (celt > static_cast<ULONG>(cfmteAvail))
		cfmte = cfmteAvail;
	else
		cfmte = celt;
	if (pceltFetched)
		*pceltFetched = cfmte;
	memcpy(rgelt, &g_rgfmte[m_ifmte], cfmte * isizeof(FORMATETC));
	m_ifmte += cfmte;
	if (m_ifmte > kcfmteLim)
		m_ifmte = kcfmteLim;
	return celt == static_cast<ULONG>(cfmte) ? S_OK : S_FALSE;

	END_COM_METHOD(g_factEnum, IID_IEnumFORMATETC);
}
Example #3
0
/*----------------------------------------------------------------------------------------------
	Perform whatever action is appropriate when the use clicks on a hot link
----------------------------------------------------------------------------------------------*/
STDMETHODIMP VwBaseVc::DoHotLinkAction(BSTR bstrData, ISilDataAccess * psda)
{
	BEGIN_COM_METHOD;
	ChkComArgPtrN(ptss);

	if (BstrLen(bstrData) > 0 && bstrData[0] == kodtExternalPathName)
	{
		StrAppBuf strbFile(bstrData + 1);
		if (::UrlIs(strbFile.Chars(), URLIS_URL))
		{
			// If it's a URL launch whatever it means.
			::ShellExecute(NULL, L"open", strbFile.Chars(), NULL, NULL, SW_SHOWNORMAL);
			return S_OK;
		}
		if (AfApp::Papp())
		{
			AfMainWnd * pafw = AfApp::Papp()->GetCurMainWnd();
			if (pafw && pafw->GetLpInfo())
				pafw->GetLpInfo()->MapExternalLink(strbFile);

			AfApp::LaunchHL(NULL, _T("open"), strbFile.Chars(), NULL, NULL, SW_SHOW);
		}
	}

	return S_OK;

	END_COM_METHOD(g_fact, IID_IVwViewConstructor);
}
Example #4
0
/*----------------------------------------------------------------------------------------------
	Read the given number of bytes from the stream / file.
----------------------------------------------------------------------------------------------*/
STDMETHODIMP FileStream::Read(void * pv, ULONG cb, ULONG * pcbRead)
{
	BEGIN_COM_METHOD;
	ChkComArrayArg((byte *)pv, cb);
	ChkComArgPtrN(pcbRead);

	if (m_hfile == NULL)
		ThrowHr(WarnHr(E_UNEXPECTED));

	if (cb == 0)
	{
		if (pcbRead)
			*pcbRead = 0;
		return S_OK;
	}

	if (!SetFilePosRaw())
		ThrowHr(WarnHr(STG_E_SEEKERROR));
	DWORD cbRead = 0;
	if (!ReadFile(m_hfile, pv, cb, &cbRead, NULL))
		ThrowHr(WarnHr(STG_E_READFAULT));
	m_ibFilePos.QuadPart += cbRead;
	if (pcbRead)
		*pcbRead = cbRead;

	END_COM_METHOD(g_fact, IID_IStream);
}
Example #5
0
/*----------------------------------------------------------------------------------------------
	Write the given number of bytes to the stream / file.
----------------------------------------------------------------------------------------------*/
STDMETHODIMP FileStream::Write(const void * pv, ULONG cb, ULONG * pcbWritten)
{
	BEGIN_COM_METHOD;
	ChkComArrayArg((byte *)pv, cb);
	ChkComArgPtrN(pcbWritten);

	if (m_hfile == NULL)
		ThrowHr(WarnHr(E_UNEXPECTED));
	if (cb == 0)
	{
		if (pcbWritten)
			*pcbWritten = 0;
		return S_OK;
	}

	if (!SetFilePosRaw())
		ThrowHr(WarnHr(STG_E_SEEKERROR));
	DWORD cbWritten = 0;
	if (!WriteFile(m_hfile, pv, cb, &cbWritten, NULL))
		ThrowHr(WarnHr(STG_E_WRITEFAULT));

	m_ibFilePos.QuadPart += cbWritten;
	if (pcbWritten)
		*pcbWritten = cbWritten;

	END_COM_METHOD(g_fact, IID_IStream);
}
Example #6
0
/*----------------------------------------------------------------------------------------------
	Store the pointer to the help topic provider, if any.
----------------------------------------------------------------------------------------------*/
STDMETHODIMP FwCppStylesDlg::putref_HelpTopicProvider(IHelpTopicProvider * phtprov)
{
    BEGIN_COM_METHOD;
    ChkComArgPtrN(phtprov);

    m_qhtprov = phtprov;

    END_COM_METHOD(g_factOPD, IID_IFwCppStylesDlg);
}
Example #7
0
/*----------------------------------------------------------------------------------------------
	Set the writing system factory for this database (or the registry, as the case may be).

	@param pwsf Pointer to the writing system factory.
----------------------------------------------------------------------------------------------*/
STDMETHODIMP FwGrEngine::putref_WritingSystemFactory(ILgWritingSystemFactory * pwsf)
{
	BEGIN_COM_METHOD
	ChkComArgPtrN(pwsf);

	m_qwsf = pwsf;

	END_COM_METHOD(g_fact, IID_IRenderEngine)
}
Example #8
0
/*----------------------------------------------------------------------------------------------
// This will set the UndoGrouper for this AH.
----------------------------------------------------------------------------------------------*/
STDMETHODIMP ActionHandler::put_UndoGrouper(IUndoGrouper * pundg)
{
	BEGIN_COM_METHOD;
	ChkComArgPtrN(pundg);

	m_qundg = pundg;

	END_COM_METHOD(g_factActh, IID_IActionHandler);
}
Example #9
0
/*----------------------------------------------------------------------------------------------
	Set the writing system factory for this simple collator.

	@param pwsf Pointer to the writing system factory that stores/produces this writing system.
----------------------------------------------------------------------------------------------*/
STDMETHODIMP LgIcuCollator::putref_WritingSystemFactory(ILgWritingSystemFactory * pwsf)
{
	BEGIN_COM_METHOD;
	ChkComArgPtrN(pwsf);

	m_qwsf = pwsf;

	END_COM_METHOD(g_fact, IID_ILgCollatingEngine);
}
Example #10
0
/*----------------------------------------------------------------------------------------------
	Store the stream pointer to the log file, if any.
----------------------------------------------------------------------------------------------*/
STDMETHODIMP FwCppStylesDlg::putref_LogFile(IStream * pstrmLog)
{
    BEGIN_COM_METHOD;
    ChkComArgPtrN(pstrmLog);

    m_qstrmLog = pstrmLog;

    END_COM_METHOD(g_factOPD, IID_IFwCppStylesDlg);
}
Example #11
0
/*----------------------------------------------------------------------------------------------
	Display the styles dialog modally and let it do its thing.
----------------------------------------------------------------------------------------------*/
STDMETHODIMP FwCppStylesDlg::ShowModal(int * pncid)
{
    BEGIN_COM_METHOD;
    ChkComArgPtrN(pncid);	// since ChkComOutPtrN doesn't exist.
    if (pncid)
        *pncid = 0;

    SetupForDoModal();
    DoModalDialog(pncid);
    GetModalResults(*pncid);

    END_COM_METHOD(g_factOPD, IID_IFwCppStylesDlg);
}
Example #12
0
/*----------------------------------------------------------------------------------------------
	Adjust the stream seek pointer, returning the new value.
	@return STG_E_SEEKERROR if the new position would be negative.
----------------------------------------------------------------------------------------------*/
STDMETHODIMP FileStream::Seek(LARGE_INTEGER dlibMove, DWORD dwOrigin,
	ULARGE_INTEGER * plibNewPosition)
{
	BEGIN_COM_METHOD;
	ChkComArgPtrN(plibNewPosition);
	if (m_hfile == NULL)
		ThrowHr(WarnHr(E_UNEXPECTED));

	DWORD dwLow;
	long dwHigh;
	LARGE_INTEGER dlibNew; // attempted new seek position

	switch (dwOrigin)
	{
	case STREAM_SEEK_SET:
		dlibNew.QuadPart = dlibMove.QuadPart;
		break;
	case STREAM_SEEK_CUR:
		dlibNew.QuadPart = (int64)m_ibFilePos.QuadPart + dlibMove.QuadPart;
		break;
	case STREAM_SEEK_END:
		// Find out where EOF is by calling for a zero move of the file pointer
		dwHigh = 0;
		dwLow = SetFilePointer(m_hfile, 0, &dwHigh, FILE_END);
		if (dwLow == 0xFFFFFFFF && GetLastError() != NO_ERROR)
			ThrowHr(WarnHr(STG_E_SEEKERROR));

		// Work out new attempted seek pointer value
		dlibNew.LowPart = dwLow;
		dlibNew.HighPart = dwHigh;
		dlibNew.QuadPart += dlibMove.QuadPart;
		break;
	default:
		ThrowHr(WarnHr(STG_E_INVALIDFUNCTION));
	}

	if (dlibNew.QuadPart < 0)
		ThrowHr(WarnHr(STG_E_SEEKERROR));

	// Update the current position.
	m_ibFilePos.QuadPart = (uint64)dlibNew.QuadPart;

	if (plibNewPosition)
		plibNewPosition->QuadPart = (uint64)dlibNew.QuadPart;

	END_COM_METHOD(g_fact, IID_IStream);
}
Example #13
0
/*----------------------------------------------------------------------------------------------
	Read a specified number of bytes from this stream into memory, starting at the current seek
	pointer.
----------------------------------------------------------------------------------------------*/
STDMETHODIMP ResourceStream::Read(void * pv, UCOMINT32 cb, UCOMINT32 * pcbRead)
{
	BEGIN_COM_METHOD;
	ChkComArrayArg((byte *)pv, cb);
	ChkComArgPtrN(pcbRead);
	UCOMINT32 cbRead;

	//Avoid reading past end of resource data.
	if (m_pbCur + cb > m_prgbData + m_cbData)
		cbRead = m_cbData - (m_pbCur - m_prgbData);
	else
		cbRead = cb;
	if (cbRead != 0)
		CopyBytes(m_pbCur, pv, cbRead);
	m_pbCur += cbRead;
	if (pcbRead)
		*pcbRead = cbRead;

	END_COM_METHOD(g_fact, IID_IStream);
}
Example #14
0
/*----------------------------------------------------------------------------------------------
	Change the seek pointer to a new location relative to the beginning of the stream, the end
	of the stream, or the current seek pointer.  ("Seek pointer" is defined as the current
	location for the next read or write operation.)
	For each calculation there is a check for overflow beforehand.
----------------------------------------------------------------------------------------------*/
STDMETHODIMP ResourceStream::Seek(LARGE_INTEGER dlibMove, DWORD dwOrigin,
	ULARGE_INTEGER * plibNewPosition)
{
	BEGIN_COM_METHOD;
	ChkComArgPtrN(plibNewPosition);

	// We can deal only with 32-bit values.
	long cbHigh = dlibMove.HighPart;
	long cbLow = dlibMove.LowPart;
	if (cbHigh != -(cbLow < 0))
		ThrowHr(WarnHr(STG_E_INVALIDPARAMETER));
	byte * pbNew;
	switch (dwOrigin)
	{
	case STREAM_SEEK_SET:
		if (cbLow < 0 || (uint)(cbLow + m_prgbData) > 0x7fffffff)
			ThrowHr(WarnHr(STG_E_INVALIDPARAMETER));
		pbNew = m_prgbData + cbLow;
		break;
	case STREAM_SEEK_CUR:
		if (m_pbCur + cbLow < m_prgbData || (uint)(cbLow + m_pbCur) > 0x7fffffff)
			ThrowHr(WarnHr(STG_E_INVALIDPARAMETER));
		pbNew = m_pbCur + cbLow;
		break;
	case STREAM_SEEK_END:
		if (m_cbData + cbLow < 0 || (uint)(cbLow + m_prgbData + m_cbData) > 0x7fffffff)
			ThrowHr(WarnHr(STG_E_INVALIDPARAMETER));
		pbNew = m_prgbData + m_cbData + cbLow;
		break;
	default:
		ThrowHr(WarnHr(STG_E_INVALIDFUNCTION));
	}

	m_pbCur = pbNew;
	if (plibNewPosition) // Note: NULL is a valid value for caller to pass.
	{
		plibNewPosition->HighPart = 0;
		plibNewPosition->LowPart = m_pbCur - m_prgbData;
	}
	END_COM_METHOD(g_fact, IID_IStream);
}
Example #15
0
/*----------------------------------------------------------------------------------------------
	Write the given number of bytes to the stream / file.
----------------------------------------------------------------------------------------------*/
STDMETHODIMP FileStream::Write(const void * pv, UCOMINT32 cb, UCOMINT32 * pcbWritten)
{
	BEGIN_COM_METHOD;
	ChkComArrayArg((byte *)pv, cb);
	ChkComArgPtrN(pcbWritten);

#if WIN32
	if (m_hfile == NULL)
		ThrowHr(WarnHr(E_UNEXPECTED));
#else
	if (m_file < 0)
		ThrowHr(WarnHr(E_UNEXPECTED));
#endif
	if (cb == 0)
	{
		if (pcbWritten)
			*pcbWritten = 0;
		return S_OK;
	}

#if WIN32
	if (!SetFilePosRaw())
		ThrowHr(WarnHr(STG_E_SEEKERROR));
	DWORD cbWritten = 0;
	if (!WriteFile(m_hfile, pv, cb, &cbWritten, NULL))
		ThrowHr(WarnHr(STG_E_WRITEFAULT));

	m_ibFilePos.QuadPart += cbWritten;
#else // !WIN32
	ssize_t cbWritten = -1;
	cbWritten = write(m_file, pv, cb);
	if (cbWritten < 0)
		ThrowHr(WarnHr(STG_E_WRITEFAULT));
#endif // !WIN32

	if (pcbWritten)
		*pcbWritten = cbWritten;

	END_COM_METHOD(g_fact, IID_IStream);
}
Example #16
0
/*----------------------------------------------------------------------------------------------
	Initialize the string crawler / database fixup process.

	@param bstrServer Name of the database server.
	@param bstrDatabase Name of the database.
	@param pstrmLog Optional output stream for logging (may be NULL).
	@param hvoRootObj Database id of the program's root object.
----------------------------------------------------------------------------------------------*/
STDMETHODIMP FwDbMergeStyles::Initialize(BSTR bstrServer, BSTR bstrDatabase, IStream * pstrmLog,
	int hvoRootObj, const GUID * pclsidApp)
{
	BEGIN_COM_METHOD;
	ChkComBstrArg(bstrServer);
	ChkComBstrArg(bstrDatabase);
	ChkComArgPtrN(pstrmLog);
	ChkComArgPtr(pclsidApp);

	m_hvoRoot = hvoRootObj;
	m_pclsidApp = pclsidApp;
	StrUni stuServer(bstrServer);
	StrUni stuDatabase(bstrDatabase);
	m_qprog.Create();
	IAdvInd3Ptr qadvi3;
	m_qprog->QueryInterface(IID_IAdvInd3, (void **)&qadvi3);
	// Note that the set of styles is different for each program.
	if (!Init(stuServer, stuDatabase, pstrmLog, qadvi3))
	{
		Terminate(m_hvoRoot);
		ThrowHr(WarnHr(E_FAIL));
	}
	END_COM_METHOD(g_fact, IID_IFwDbMergeStyles);
}
Example #17
0
/*----------------------------------------------------------------------------------------------
	The standard method for generating a segment in a paragraph, where a line break might be
	necessary.

	Generally called with fEndLine true; then change segment to make it false if we want to
	try to put something else after.

	TODO SharonC?: try implementing and see whether we can handle all the possible complications relating
	to adjacent segments that can't be separated, such as English parens around Hebrew text.

	@param pgjus		- NULL if no justification will ever be needed for the resulting segment
	@param ichMin/Lim			- part of string to use
	@param ichwLimBacktrack		- when backtracking, where to start looking for a new break
	@param fNeedFinalBreak		- if false, assume it is okay to make a segment ending at
									ichwLim; if true, assume the text source has at least one
									more character at ichwLim, and end the segment at ichwLim
									only if that is a valid break point
	@param fStartLine			- seg is logically first on line? (we assume it is logically last)
	@param dxMaxWidth			- available width in x coords of graphics object
	@param lbPref				- try for longest segment ending with this breakweight
	@param lbMax				- max (last resort) breakweight if no preferred break possible
	@param twsh					- how we are handling trailing white-space
	@param fParaRtl				- overall paragraph direction
	@param pplsegRet			- segment produced, or null if nothing fits
	@param pichwLimSeg			- end of segment produced, beginning of next
	@param pdxWidth				- width of newly-created segment
	@param pest					- what caused the segment to end
	@param cpPrev				- byte size of pbPrevSegDat buffer
	@param pbPrevSegDat			- for initializing from previous segment
	@param cbNextMax			- max size of pbNextSegDat buffer
	@param pbNextSegDat			- for initializing next segment
	@param pcbNextSegDat		- size of pbNextSegDat buffer
	@param pdichwContext		- for the following segment, the index of the first char of
									interest to it; ie, edits before this character will not
									affect how the next segment behaves
----------------------------------------------------------------------------------------------*/
STDMETHODIMP FwGrEngine::FindBreakPoint(
	IVwGraphics * pvg, IVwTextSource * pts, IVwJustifier * pvjus,
	int ichwMin, int ichwLim, int ichwLimBacktrack,
	ComBool fNeedFinalBreak,
	ComBool fStartLine,
	int dxMaxWidth,
	LgLineBreak lbPref, LgLineBreak lbMax,
	LgTrailingWsHandling twsh, ComBool fParaRtl,
	ILgSegment ** ppsegRet,
	int * pdichwLimSeg,
	int * pdxWidth, LgEndSegmentType * pest,
	ILgSegment * plgsegPrev)
{
	BEGIN_COM_METHOD;
	ChkComArgPtr(pvg);
	ChkComArgPtr(pts);
	ChkComArgPtrN(pvjus);
	ChkComOutPtr(ppsegRet);
	ChkComOutPtr(pdichwLimSeg);
	ChkComArgPtr(pdxWidth);
	ChkComArgPtr(pest);

	HRESULT hr = S_OK;

	// Use wrappers that fit what is expected by the Graphite implementation code:
	//////FwGrGraphics gg(pvg);

	// Create these on the heap so they can be stored in the segment.
	FwGrTxtSrc * pgts = new FwGrTxtSrc(pts, m_useNFC);
	//FwGrJustifier * pgjus = (pvjus) ? new FwGrJustifier(pvjus) : NULL;
	if (pvjus && !s_pgjus)
	{
		s_pgjus = new FwGrJustifier(pvjus);
		m_pgjus = s_pgjus; // make this engine responsible for deleting it
	}

	FwGrSegmentPtr qfwgrseg;
	if (*ppsegRet)
	{
		return E_INVALIDARG;
		//CheckHr((*ppsegRet)->QueryInterface(CLSID_FwGrSegment, (void**)&qfwgrseg));
		//pgrseg = qfwgrseg->GraphiteSegment();
	}

	Segment * psegPrev = NULL;
	if (plgsegPrev)
	{
		FwGrSegment * pfwgrseg = dynamic_cast<FwGrSegment *>(plgsegPrev);
		if (pfwgrseg)
			psegPrev = pfwgrseg->GraphiteSegment();
		// otherwise, not a Graphite segment
	}

	// Need-final-break is true if and only if we are backtracking.
	Assert((ichwLim != ichwLimBacktrack) == fNeedFinalBreak);

	// Adjust the font in the graphics device for super/subscripting.

	SetUpGraphics(pvg, pgts, ichwMin);

	HDC hdc;
	IVwGraphicsWin32Ptr qvg32;
	CheckHr(pvg->QueryInterface(IID_IVwGraphicsWin32, (void **)&qvg32));
	CheckHr(qvg32->GetDeviceContext(&hdc));
	////gg.GetDeviceContext(&hdc);

	Segment * pgrseg;
	WinFont * pfontSeg;
	try
	{
		// DON'T use m_pfont, which might be for the wrong size; use a new font
		// specifically for this size font.
		FwWinFont font(hdc);
		int xInch, yInch;
		pvg->get_XUnitsPerInch(&xInch);
		pvg->get_YUnitsPerInch(&yInch);
		font.SetDPI(xInch, yInch);

		std::ofstream strmLog;
		std::ostream * pstrmLog = CreateLogFile(strmLog, (psegPrev != NULL));

		// for testing UTF-8:
		//gr::utf16 prgchw[1000];
		//int cchwLen;
		//pts->get_Length(&cchwLen);
		//pts->Fetch(ichwMin, cchwLen, prgchw);
		//ichwLim = CountUtf8FromUtf16(prgchw, ichwLim);
		//ichwLimBacktrack = ichwLim;
		/////////////////////

		LayoutEnvironment layout;
		layout.setStartOfLine(fStartLine);
		layout.setEndOfLine(true);
		layout.setBestBreak(lbPref);
		layout.setWorstBreak(lbMax);
		layout.setRightToLeft(fParaRtl);
		layout.setTrailingWs(twsh);
		layout.setPrevSegment(psegPrev);
		layout.setJustifier(s_pgjus);
		layout.setLoggingStream(pstrmLog);
		layout.setDumbFallback(true);

		//for allowing hyphen breaks:
		//layout.setBestBreak(max(klbHyphenBreak, lbPref));
		//layout.setWorstBreak(max(klbHyphenBreak, lbMax));

		bool fBacktracking = (ichwLimBacktrack < ichwLim);
		int grIchwMin = pgts->VwToGrOffset(ichwMin);
		int grIchwLim = fBacktracking ? pgts->VwToGrOffset(ichwLimBacktrack) : pgts->VwToGrOffset(ichwLim);

		pgrseg = new LineFillSegment(&font, pgts, &layout,
			grIchwMin, grIchwLim,
			(float)dxMaxWidth, fBacktracking);
		gr::Font & fontSeg = pgrseg->getFont();
		pfontSeg = dynamic_cast<WinFont *>(&fontSeg);
		pfontSeg->replaceDC(hdc);
		*pest = pgrseg->segmentTermination();
		if (*pest != kestNothingFit)
		{
			int grIchwLimSeg = pgrseg->stopCharacter() - pgrseg->startCharacter();
			*pdichwLimSeg = pgts->GrToVwOffset(grIchwLimSeg);
			*pdxWidth = gr::GrEngine::RoundFloat(pgrseg->advanceWidth());
			// there is a limit in the number of pixels (about 2^16) that the ExtTextOut function
			// can render, which is what Graphite uses to render text on Windows. If this
			// segment is over that limit, we reduce the number of characters in this segment
			// so that when it is rendered it is less than the limit. The main place this
			// can happen is in concordance views.
			// TODO (DamienD): This fix removes characters from the end of the segment. If the
			// segment is too long on the left side of the arrow in the concordance view,
			// characters should be removed from the beginning. This case would have to be
			// handled in Views somewhere.
			// TODO (DamienD): If Graphite ever fixes the limit, we can safely remove this
			// hack.
			if (*pdxWidth > SHRT_MAX)
			{
				delete pgrseg;
				int avgCharWidth = *pdxWidth / (grIchwMin + grIchwLimSeg);
				// we use 30000 here, because avgCharWidth is just an estimate,
				// this gives us some padding to ensure that the resulting segment
				// is less than the limit
				grIchwLim = grIchwMin + (30000 / avgCharWidth);
				pgrseg = new LineFillSegment(&font, pgts, &layout,
					grIchwMin, grIchwLim,
					(float)dxMaxWidth, fBacktracking);

				// reset variables for new segment
				gr::Font & fontSeg = pgrseg->getFont();
				pfontSeg = dynamic_cast<WinFont *>(&fontSeg);
				pfontSeg->replaceDC(hdc);

				*pest = pgrseg->segmentTermination();
				if (*pest != kestNothingFit)
				{
					*pdichwLimSeg = pgts->GrToVwOffset(pgrseg->stopCharacter() - pgrseg->startCharacter());
					*pdxWidth = gr::GrEngine::RoundFloat(pgrseg->advanceWidth());
				}
			}
		}

		strmLog.close();
	}
	catch (FontException & fexptn)
	{
		// Error in initializing the font.
		FontErrorCode ferr = fexptn.errorCode;
		LgCharRenderProps chrp;
		int ichwMinBogus, ichwLimBogus;
		pgts->GetCharProps(ichwMin, &chrp, &ichwMinBogus, &ichwLimBogus);
		StrUni stuMsg = L"Error in initializing Graphite font ";
		stuMsg.Append(chrp.szFaceName);
		stuMsg.Append(": ");
		std::wstring stuErrMsg = FontLoadErrorDescription(ferr, 0, 0, &hr);
		stuMsg.Append(stuErrMsg.c_str());
		StackDumper::RecordError(IID_IRenderEngine, stuMsg, L"SIL.Graphite.FwGrEngine", 0, L"");
		return hr;
	}

	// if we are at the end of the requested range, but the text source still has more text in
	// it, Graphite will determine that the break was bad or okay, even though it broke
	// because there was no more text, so we go ahead and change the reason here to no more text
	if (ichwMin + *pdichwLimSeg == ichwLim && (*pest == kestOkayBreak || *pest == kestBadBreak))
		*pest = kestNoMore;

	bool fError = false;
	std::pair<GlyphIterator, GlyphIterator> pairGfit = pgrseg->glyphs();
	GlyphIterator gfit = pairGfit.first;
	GlyphIterator gfitEnd = pairGfit.second;
	for ( ; gfit != gfitEnd ; ++gfit)
	{
		if ((*gfit).erroneous())
		{
			fError = true;
			break;
		}
	}

	if (fError)
	{
		LgCharRenderProps chrp;
		int ichwMinBogus, ichwLimBogus;
		pgts->GetCharProps(ichwMin, &chrp, &ichwMinBogus, &ichwLimBogus);
		StrUni stuMsg = L"Error in Graphite rendering using font ";
		stuMsg.Append(chrp.szFaceName);
		StackDumper::RecordError(IID_IRenderEngine, stuMsg, L"SIL.Graphite.FwGrEngine", 0, L"");
		hr = E_FAIL;
	}

	//// TEMPORARY - for testing
	//pairGfit = pgrseg->glyphs();
	//gfit = pairGfit.first;
	//gfitEnd = pairGfit.second;
	//for ( ; gfit != gfitEnd ; ++gfit)
	//{
	//	GlyphInfo ginf = *gfit;
	//	gid16 gid = ginf.glyphID();
	//	gid = ginf.pseudoGlyphID();

	//	int n = ginf.logicalIndex();
	//	float xy = ginf.origin();
	//	xy = ginf.advanceWidth();
	//	xy = ginf.advanceHeight();
	//	xy = ginf.yOffset();
	//	gr::Rect bb = ginf.bb();
	//	bool f = ginf.isSpace();
	//	f = ginf.insertBefore();
	//	toffset ich = ginf.firstChar();
	//	int ich = ginf.lastChar();
	//	unsigned int dir = ginf.directionality();
	//	dir = ginf.directionLevel();
	//	n = ginf.attachedTo();

	//	n = ginf.numberOfComponents();
	//	for (int i = 0; i < n; i++)
	//	{
	//		bb = ginf.componentBox(i);
	//		ich = ginf.componentFirstChar(i);
	//	}

	//	std::pair<GlyphIterator, GlyphIterator> pairGlyphRange
	//		= pgrseg->charToGlyphs(ginf.firstChar());

	//	for ( ; pairGlyphRange.first != pairGlyphRange.second ; ++(pairGlyphRange.first))
	//	{
	//		ginf = *pairGlyphRange.first;
	//		gid = ginf.glyphID();
	//	}
	//}

	//// for testing:
	//int rgigbb[100];
	//bool rgfClusterStart[100];
	//int cch, cf;
	//pgrseg->getUniscribeClusters(rgigbb, 100, &cch, rgfClusterStart, 100, &cf);

	//// for testing
	//for (int dxWidth = 50; dxWidth < 500; dxWidth += 50)
	//{
	//	int ichBreak;
	//	float dxRetWidth;
	//	ichBreak = pgrseg->findNextBreakPoint(4, klbWsBreak, klbWsBreak, (float)dxWidth, &dxRetWidth, false, false);
	//	int x;
	//	x = 3;
	//}

	pfontSeg->restoreDC();

	// Even if there was an error, if a segment was created, we want to return it.

	if (pgrseg && (*pest != kestNothingFit))
	{
		////qfwgrseg = dynamic_cast<FwGrSegment *>(pgrseg);
		////Assert(qfwgrseg);

		FwGrSegment * psegTmp;
		if (!qfwgrseg)
		{
			psegTmp = NewObj FwGrSegment;
			qfwgrseg = dynamic_cast<FwGrSegment *>(psegTmp);
			Assert(qfwgrseg);
		}
		else
			psegTmp = qfwgrseg.Ptr();

		qfwgrseg->SetGraphiteSegment(pgrseg);

		HRESULT hrTmp;
		CheckHr(hrTmp = qfwgrseg->QueryInterface(IID_ILgSegment, (void **)ppsegRet));
		if (FAILED(hrTmp))
			hr = hrTmp;
		////pgrseg->DecRefCount();
		psegTmp->Release();

		qfwgrseg->SetFwGrEngine(this);
		qfwgrseg->SetTextSource(pgts);

		//pgts->IncRefCount();	// not needed; pgts holds a smart pointer that increments
								// the ref count on the FW text source
	}
	else
	{
		delete pgrseg;
		delete pgts;
		qfwgrseg = NULL;
	}

	return hr;

	END_COM_METHOD(g_fact, IID_IRenderEngine);
}
Example #18
0
/*----------------------------------------------------------------------------------------------
Replace
	The default implementation just replaces characters from ichMin to ichLim with
	those from bstrInput, then set *pichModMin to ichMin, and *pichModLim and
	*pichIP both to ichMin + BstrLen(bstrInput).

	 Arguments:
		bstrInput				what user typed
		pttpInput          		text properties desired for new text
		ptsbOld        			original, unedited text, gets modified
		ichMin,	ichLim			range in original to replace
		pichModMin, pichModLim  range in output text affected
		pichIP                  position of IP in modified string

----------------------------------------------------------------------------------------------*/
STDMETHODIMP LgInputMethodEditor::Replace(BSTR bstrInput, ITsTextProps * pttpInput,
		ITsStrBldr * ptsbOld, int ichMin, int ichLim, int * pichModMin, int * pichModLim,
		int * pichIP)
{
	BEGIN_COM_METHOD;
	ChkComBstrArgN(bstrInput);
	ChkComArgPtrN(pttpInput);
	ChkComArgPtr(ptsbOld);
	ChkComOutPtr(pichModMin);
	ChkComOutPtr(pichModLim);
	ChkComOutPtr(pichIP);

	int cCh;
	SmartBstr sbstr;
	CheckHr(ptsbOld->get_Length(&cCh));
	if (ichMin < 0 || ichLim > cCh || ichMin > ichLim)
	{
		*pichModMin = 0;
		*pichModLim = 0;
		*pichIP = 0;
		ThrowHr(WarnHr(E_INVALIDARG));
	}

	// Check to make sure the ichMin is not between a surrognte pair.
	do
	{
		if (0 < ichMin)
		{
			CheckHr(ptsbOld->GetChars(ichMin, ichMin + 1, &sbstr));
			if (sbstr[0] < 0xDC00 || sbstr[0] > 0xDFFF)
				break;
		}
		else
		{
			break;
		}
	} while (--ichMin > 0);

	// Check to make sure the ichLim is not between a surrgante pair.
	do
	{
		if (cCh > ichLim)
		{
			CheckHr(ptsbOld->GetChars(ichLim, ichLim + 1, &sbstr));
			if (sbstr[0] < 0xDC00 || sbstr[0] > 0xDFFF)
				break;
		}
		else
		{
			break;
		}
	} while (++ichLim < cCh);

	// Now, do the real work

	CheckHr(ptsbOld->Replace(ichMin, ichLim, bstrInput, pttpInput));
	*pichModMin = ichMin;
	*pichModLim = ichMin + BstrLen(bstrInput);
	*pichIP = ichMin + BstrLen(bstrInput);

	END_COM_METHOD(g_fact, IID_ILgFontManager);
}
Example #19
0
/*----------------------------------------------------------------------------------------------
	Make a segment by finding a suitable break point in the specified range of text.
	Note that it is appropriate for line layout to use this routine even if putting
	text on a single line, because an old writing system may take advantage of line layout
	to handle direction changes and style changes and generate multiple segments
	even on one line. For such layouts, pass a large dxMaxWidth, but still expect
	possibly multiple segments.
	Arguments:
		pgjus				NULL if no justification will ever be needed for the resulting segment
		ichMinNew			index of the first char in the text that is of interest
		ichLimText			index of the last char in the text that is of interest (+ 1)
		ichLimBacktrack		index of last char that may be included in the segment.
							Generally the same as ichLimText unless backtracking.
		fNeedFinalBreak
		fStartLine			seg is logically first on line?
		dxMaxWidth			whatever coords pvg is using
		lbPref				try for longest seg of this weight
		lbMax				max if no preferred break possible
		twsh				how we are handling trailing white-space
		fParaRtoL			overall paragraph direction
		ppsegRet			segment produced, or null if nothing fits
		pdichLimSeg			offset to last char of segment, first of next if any
		pdxWidth			of new segment, if any
		pest				what caused the segment to end?
		cbPrev				(not used)
		pbPrevSegDat		(not used)
		cbNextMax			(not used)
		pbNextSegDat		(not used)
		pcbNextSegDat		(*pcbNextSegDat always set to zero)
		pdichContext		(*pdichContext always set to zero)

	TODO 1441 (SharonC): handle fParaRtoL; specifically, if the paragraph direction is
	right-to-left, trailing white-space characters should be reversed.
----------------------------------------------------------------------------------------------*/
STDMETHODIMP RomRenderEngine::FindBreakPoint(
	IVwGraphics * pvg, IVwTextSource * pts, IVwJustifier * pvjus,
	int ichMinNew, int ichLimText, int ichLimBacktrack,
	ComBool fNeedFinalBreak, ComBool fStartLine,
	int dxMaxWidth, LgLineBreak lbPref, LgLineBreak lbMax,
	LgTrailingWsHandling twsh, ComBool fParaRtoL,
	ILgSegment ** ppsegRet, int * pdichLimSeg, int * pdxWidth, LgEndSegmentType * pest,
	ILgSegment * psegPrev)
{
	BEGIN_COM_METHOD
	ChkComArgPtr(pvg);
	ChkComArgPtr(pts);
	ChkComOutPtr(ppsegRet);
	ChkComOutPtr(pdichLimSeg);
	ChkComArgPtr(pdxWidth);
	ChkComArgPtr(pest);
	ChkComArgPtrN(psegPrev);
#define INIT_BUF_SIZE 1000
	OLECHAR rgchBuf[INIT_BUF_SIZE]; // Unlikely segments are longer than this...
	memset(rgchBuf, 0, sizeof(rgchBuf));
	Vector<OLECHAR> vch; // Use as buffer if 1000 is not enough
	OLECHAR * prgch = rgchBuf; // Use on-stack variable if big enough
	int cchBuf = INIT_BUF_SIZE; // chars available in prgch; INIT_BUF_SIZE or vch.Size().

	int ichForceBreak;
	byte rglbsBuf[INIT_BUF_SIZE]; // line break status
	Vector<byte> vlbs;
	byte * prglbsForString = rglbsBuf; // switch to resized vector if needed.

	RomRenderSegmentPtr qrrs;
	LgCharRenderProps chrp;
	int ichMinRun, ichLimRun;
	CheckHr(pts->GetCharProps(ichMinNew, &chrp, &ichMinRun, &ichLimRun));
	// Ws and old writing system for the segment; don't use chars with different ones.
	int ws = chrp.ws;
	int nDirDepth = chrp.nDirDepth;
	if (fParaRtoL)
		nDirDepth += 2;
	//Assert((nDirDepth % 2) == 0); // left-to-right

	// Get a char props engine
	AssertPtr(m_qwsf);
	ILgCharacterPropertyEnginePtr qcpe;
	CheckHr(m_qwsf->get_CharPropEngine(ws, &qcpe));

// The maximum number of characters we will fetch and measure, beyond what we
// know we need. This should be less than the length of rgchBuf.
#define MAX_MEASURE 100
	EndAvailType eat;
	int ichLimSegCur; // Current proposal for where seg might end
	// We aren't allowed to include characters at or beyond ichLimBacktrack in the
	// segment. But it's worth getting one more, if more are available, so we can
	// check whether an line break at the very end is allowed.
	// Note that this time we're getting at most MAX_MEASURE chars, so we don't
	// have to check for buffer overflow.
	GetAvailChars(pts, ws, ichMinNew, ichLimBacktrack, MAX_MEASURE, twsh, qcpe,
		prgch, &ichLimSegCur, &eat);

	// Measure all the characters we got, or all we are allowed to use, whichever
	// is less.
	int cchMeasure = ichLimSegCur - ichMinNew;
	// Make a segment to use in measuring things; if all goes well use it for the
	// final result.
	qrrs.Attach(NewObj RomRenderSegment(pts, this, cchMeasure,
		klbNoBreak, klbNoBreak, true));
	qrrs->SetDirectionInfo(nDirDepth, (twsh == ktwshOnlyWs));

	// If a forced empty segment, stop here
	if (ichLimBacktrack <= ichMinNew)
	{
		*pest = kestNoMore;
		*pdxWidth = 0;
		*ppsegRet = qrrs.Detach();
		*pdichLimSeg = 0;
		return S_OK;
	}

	int dxWidthMeasure = 0; // width of part of run initially measured.

	CheckHr(qrrs->get_Width(ichMinNew, pvg, &dxWidthMeasure));

	int cchLineEst; // Calculate the estimated number of characters to fill line.
	int cchMaxText = ichLimBacktrack - ichMinNew;
#ifdef ICU_LINEBREAKING
	int ichTempBreak;
	LgLineBreak lbWeight;
	LgGeneralCharCategory cc;
#endif /*ICU_LINEBREAKING*/

	// Now, if it is a short text or already contains all candidate characters,
	// we have the actual width; otherwise, we have
	// a measurement of MAX_MEASURE characters that we can use in guessing how many we
	// need. If we have less than we need, increase the limit until we have more.
	// Note that we need the <= here because, if we have exactly filled the width, we
	// will consider putting a break after the MAX_MEASURE'th character. We need to
	// fetch at least one more character in order to have valid line-break info
	// about the last one that might be put on the line.
	while (eat == keatMax && ichLimSegCur < ichLimBacktrack && dxWidthMeasure <= dxMaxWidth)
	{
		// Compute the number we estimate will fill the line (min the number we have).
		// Don't let this estimate be zero unless we actually have no characters available.
		if (!dxWidthMeasure)
			cchLineEst = min(max(1, dxMaxWidth * cchMeasure), cchMaxText);
		else
			// Use MulDiv to avoid overflow, likely when dxMaxWidth is INT_MAX
			cchLineEst = min(max(1, MulDiv(dxMaxWidth, cchMeasure, dxWidthMeasure)), cchMaxText);
		// Make sure the buffer contains MAX_MEASURE more than that. First make sure
		// there is room for them.
		// We have already loaded out to ichLimSegCur, so use that as a start position.
		// Already in the buffer are pts[ichMinNew...ichLimSegCur] starting at prgch.
		// We need room for cchLineEst + MAX_MEASURE, but add a few more to buffer size
		// so we are always safe adding one or two for end of line testing.
		if (cchLineEst + MAX_MEASURE + 5 >= cchBuf)
		{
			// Allocate memory for the characters in the vector, or resize it.
			// Allocate extra in case we keep adding later.
			cchBuf = cchLineEst + MAX_MEASURE + 500;
			vch.Resize(cchBuf);
			if (prgch == rgchBuf)
				MoveItems(rgchBuf, vch.Begin(), ichLimSegCur - ichMinNew);
			prgch = vch.Begin();
			vlbs.Clear();  // no need to copy, nothing in it yet.
			vlbs.Resize(cchBuf);
			prglbsForString = vlbs.Begin();
		}
		GetAvailChars(pts, ws, ichLimSegCur, ichLimBacktrack,
			ichMinNew + cchLineEst + MAX_MEASURE - ichLimSegCur, twsh, qcpe,
			prgch + ichLimSegCur - ichMinNew, &ichLimSegCur, &eat);
		cchMeasure = ichLimSegCur - ichMinNew;
		qrrs->SetLim(cchMeasure);
		qrrs->SetDirectionInfo(nDirDepth, (twsh == ktwshOnlyWs));
		CheckHr(qrrs->get_Width(ichMinNew, pvg, &dxWidthMeasure));
	}

#ifdef ICU_LINEBREAKING
	//updating the BreakIterator text for calculating line breaks later
	CheckHr(qcpe->put_LineBreakText(prgch, ichLimSegCur-ichMinNew));
#endif /*ICU_LINEBREAKING*/

	// Update this with the results of the latest measurement.
	if (!dxWidthMeasure)
		cchLineEst = min(max(1, dxMaxWidth * cchMeasure), cchMaxText);
	else
		// Use MulDiv to avoid overflow, likely when dxMaxWidth is INT_MAX
		cchLineEst = min(max(1, MulDiv(dxMaxWidth, cchMeasure, dxWidthMeasure)), cchMaxText);
	// Now we have measured either all the characters we are allowed, or enough to
	// fill the line.

	if (dxWidthMeasure <= dxMaxWidth)
	{
		// we will most likely answer the segment we just found
		*pdxWidth = dxWidthMeasure;
		*pdichLimSeg = min(ichLimSegCur - ichMinNew, ichLimBacktrack - ichMinNew);
		if (ichLimSegCur == ichLimText)
		{
			// the whole text we were asked to use fit
			*pest = kestNoMore;
			*ppsegRet = qrrs.Detach();
			return S_OK;
		}
		if (ichLimSegCur == ichLimBacktrack)
		{
			// Everything allowed fits, but, since this is not the real end of the text,
			// we have to consider whether this is a valid line break. We will need one
			// more character in the buffer. We made sure above there is room for it.
			CheckHr(pts->Fetch(ichLimSegCur, ichLimSegCur + 1, prgch + ichLimSegCur - ichMinNew));
			// We want to get line break info for the character at ichLimSegCur - 1, relative to
			// the string as a whole. Offset relative to buffer is less by ichMinNew.
			int ichBuf = ichLimSegCur - ichMinNew - 1;
#ifndef ICU_LINEBREAKING
			CheckHr(qcpe->GetLineBreakInfo(prgch, ichLimSegCur - ichMinNew + 1,
				ichBuf, ichBuf + 1, prglbsForString, &ichForceBreak));
#else
			//updating the BreakIterator text for calculating line breaks
			CheckHr(qcpe->put_LineBreakText(prgch, ichLimSegCur-ichMinNew+1));
			CheckHr(qcpe->LineBreakAfter(ichBuf, &ichTempBreak, &lbWeight));
// Previous code was wrong twice:
// 1. did not offset by ichMinNew
// 2. did not allow GetLineBreakInfo to use info about characters earlier in run.
// Also it got one more result than we need.
//			CheckHr(qcpe->GetLineBreakInfo(prgch + ichLimSegCur - 1, 2, 0, 2, prglbsForString,
//				&ichForceBreak));
			CheckHr(qcpe->get_GeneralCategory(prgch[ichBuf], &cc));
			if ((ichTempBreak == ichBuf+1) && (cc == kccZs))
#endif /*ICU_LINEBREAKING*/
#ifndef ICU_LINEBREAKING
			if (prglbsForString[0] & kflbsBrk)
#endif /*ICU_LINEBREAKING*/
			{
				// Backtrack posn is also a line break
				*pest = kestOkayBreak;
				*ppsegRet = qrrs.Detach();
				return S_OK;
			}
			else if (!fNeedFinalBreak)
			{
				// Backtrack position is not a break, but we may return it anyway
				// This probably never happens but include it for consistency.
				*pest = kestBadBreak;
				*ppsegRet = qrrs.Detach();
				return S_OK;
			}
			// If we get here we must search for an earlier break.
			goto LFindEarlierBreak;
		}
		if (eat == keatBreak || eat == keatOnlyWs)
		{
			*pest = (eat == keatOnlyWs) ? kestOkayBreak : kestHardBreak;
			// a segment up to a hard return or similar fit
			// Return the segment we got (which may be an empty segment)
			*ppsegRet = qrrs.Detach();
			return S_OK;
		}
		// Only one reason remains for us to have stopped while not filling the width
		Assert(eat == keatNewWs);
		// See whether the WS break is also a line break.
		// We want to get line break info for the character at ichLimSegCur - 1, relative to
		// the string as a whole. Offset relative to buffer is less by ichMinNew.
		int ichBuf = ichLimSegCur - ichMinNew - 1;
#ifndef ICU_LINEBREAKING
		CheckHr(qcpe->GetLineBreakInfo(prgch, ichLimSegCur - ichMinNew,
			ichBuf, ichBuf + 1, prglbsForString, &ichForceBreak));
#else
		CheckHr(qcpe->LineBreakAfter(ichBuf, &ichTempBreak, &lbWeight));

		CheckHr(qcpe->get_GeneralCategory(prgch[ichBuf], &cc));
		if ((ichTempBreak == ichBuf+1) && (cc == kccZs))
#endif /*ICU_LINEBREAKING*/
#ifndef ICU_LINEBREAKING
		if (prglbsForString[0] & kflbsBrk)
#endif /*ICU_LINEBREAKING*/
		{
			// WS break is also a line break
			*pest = kestOkayBreak;
			*ppsegRet = qrrs.Detach();
			return S_OK;
		}
		else
		{
			if (!fNeedFinalBreak)
			{
				// Though not a line break, return it and see if we can fit some
				// of next WS on to make things OK.
				*pest = kestWsBreak;
				*ppsegRet = qrrs.Detach();
				return S_OK;
			}
			// otherwise, fall through to find a valid line break earlier.
		}
	}

LFindEarlierBreak:
	// ENHANCE JohnT: arguably we ought to look further back to be absolutely sure
	// of line break props. It makes a difference only if old writing system changes
	// in middle of a run of spaces or combining marks, and even then, the extra spaces
	// will fit so we shouldn't make a spurious break, and the run of CMs should only
	// get broken if the column is too narrow for a whole word. I think we can live
	// wit this.
	// Note: we can ignore ichForceBreak here because we made sure in GetAvailChars
	// that there aren't any break characters before ichLimSegCur.
	CheckHr(qcpe->GetLineBreakInfo(prgch, ichLimSegCur - ichMinNew, 0,
		ichLimSegCur - ichMinNew, prglbsForString, &ichForceBreak));

	// If we got here, we will have to make a line break within the run, somewhere
	// before ichLimSegCur, since stopping there either makes it too wide, or violates
	// fNeedFinalBreak.
	*pest = kestMoreLines;

	// broken segment will certainly end line
	CheckHr(qrrs->put_EndLine(ichMinNew, pvg, true));

	// Get info about line break possibilities

	// Figure the best kind of line break we can do at all,
	// starting at lbPref
	LgLineBreak lbTry;
	lbTry = lbPref;	// sep from decl because of goto
	int ichBreak;	// index in prglbsForString of character after which break is allowed at
					// given level
	int ichDim;		// index in prglbsForString of last character before ichBreak which is
					// not a space,
	ichBreak = -1;	// don't init in decl because of goto
	int dxBreakWidth;
	// loop over possible levels of badness of break, from lbPref to lbMax.
	for (;;)
	{
		if (!(lbTry == klbHyphenBreak && lbTry != lbPref))
		{
			// Look for a break at this level. The condition above means
			// don't try hyphen break if we already tried word break.
			// This engine can't (yet) find a hyphen break that is not
			// a word break.
#ifndef ICU_LINEBREAKING
			FindLineBreak(prglbsForString, 0, ichLimSegCur - ichMinNew, lbTry, false,
				ichBreak, ichDim);
#else
			FindLineBreak(prgch, qcpe, 0, ichLimSegCur - ichMinNew, lbTry, false,
				ichBreak, ichDim);
#endif /*ICU_LINEBREAKING*/
			if (ichBreak >= 0)
			{
				if (ichDim < 0)
					break;		// all characters up to break are spaces
				qrrs->SetLim(ichDim + 1);
				qrrs->SetDirectionInfo(nDirDepth, (twsh == ktwshOnlyWs));
				CheckHr(qrrs->get_Width(ichMinNew, pvg, &dxBreakWidth));
				if (dxBreakWidth > dxMaxWidth && lbTry < klbClipBreak)
				{
					// can't do this kind of break
					ichBreak = -1;
				}
			}
			if (ichBreak >= 0)
				break;		// found a useable break at this level
		}
		lbTry = (LgLineBreak) (lbTry + 1);	// otherwise try next level.
		if (lbTry > lbMax)
		{
			// can't get any valid break. Give up.
			*ppsegRet = NULL;
			*pdxWidth = 0;
			return S_OK;  // this is a perfectly valid result.
		}
		Assert(lbTry <= klbClipBreak); // that level should always succeed
	}
	// OK, we are going to put something on the line. The break type will be lbTry.
	// See if we can find any later breaks of the same type that fit.

	int ichNewBreak;		// in prglbsForString
	int ichNewDim = -1;		// in prglbsForString
	int dxNewBreakWidth;

	// 1. look backward for first break prior to cchLineEst
	// 2. while break doesn't fit, look backward for next prior break
	// 3. once a break fits, quit and use it.
	// 4. while break fits, remember it and look forward for next following break
	// 5. once a break doesn't fit, quit and use the previous break.

	bool fLookAhead = true;
	if (cchLineEst > ichBreak)
#ifndef ICU_LINEBREAKING
		FindLineBreak(prglbsForString, ichBreak + 1, cchLineEst, lbTry, true, ichNewBreak,
			ichNewDim);
#else
		FindLineBreak(prgch, qcpe, ichBreak + 1, cchLineEst, lbTry, true, ichNewBreak,
			ichNewDim);
#endif /*ICU_LINEBREAKING*/
	else
Example #20
0
/*----------------------------------------------------------------------------------------------
	Adjust the stream seek pointer, returning the new value.
	@return STG_E_SEEKERROR if the new position would be negative.
----------------------------------------------------------------------------------------------*/
STDMETHODIMP FileStream::Seek(LARGE_INTEGER dlibMove, DWORD dwOrigin,
	ULARGE_INTEGER * plibNewPosition)
{
	BEGIN_COM_METHOD;
	ChkComArgPtrN(plibNewPosition);

#if WIN32
	if (m_hfile == NULL)
		ThrowHr(WarnHr(E_UNEXPECTED));

	DWORD dwLow;
	long dwHigh;
	LARGE_INTEGER dlibNew; // attempted new seek position

	switch (dwOrigin)
	{
	case STREAM_SEEK_SET:
		dlibNew.QuadPart = dlibMove.QuadPart;
		break;
	case STREAM_SEEK_CUR:
		dlibNew.QuadPart = (int64)m_ibFilePos.QuadPart + dlibMove.QuadPart;
		break;
	case STREAM_SEEK_END:
		// Find out where EOF is by calling for a zero move of the file pointer
		dwHigh = 0;
		dwLow = SetFilePointer(m_hfile, 0, &dwHigh, FILE_END);
		if (dwLow == 0xFFFFFFFF && GetLastError() != NO_ERROR)
			ThrowHr(WarnHr(STG_E_SEEKERROR));

		// Work out new attempted seek pointer value
		dlibNew.LowPart = dwLow;
		dlibNew.HighPart = dwHigh;
		dlibNew.QuadPart += dlibMove.QuadPart;
		break;
	default:
		ThrowHr(WarnHr(STG_E_INVALIDFUNCTION));
	}

	if (dlibNew.QuadPart < 0)
		ThrowHr(WarnHr(STG_E_SEEKERROR));

	// Update the current position.
	m_ibFilePos.QuadPart = (uint64)dlibNew.QuadPart;

	if (plibNewPosition)
		plibNewPosition->QuadPart = (uint64)dlibNew.QuadPart;
#else
	// TODO-Linux: Examine for cross-platform compatibility what was introduced with r576 and semi-addressed in r1482.
	// TODO-Linux: Check correct behavior for seek past EOF
	if (m_file < 0)
		ThrowHr(WarnHr(E_UNEXPECTED));
	off_t dMove = dlibMove.QuadPart;
	if (dMove != dlibMove.QuadPart) {
		return WarnHr(E_UNEXPECTED);
	}

	int whence;

	switch (dwOrigin)
	{
	case STREAM_SEEK_SET:
		whence = SEEK_SET;
		break;
	case STREAM_SEEK_CUR:
		whence = SEEK_CUR;
		break;
	case STREAM_SEEK_END:
		whence = SEEK_END;
		break;
	default:
		ThrowHr(WarnHr(STG_E_INVALIDFUNCTION));
	}

	off_t newPos = lseek(m_file, dMove, whence);

	if (newPos < 0) {
		ThrowHr(WarnHr(STG_E_SEEKERROR));
	}

	if (plibNewPosition) {
		plibNewPosition->QuadPart = newPos;
	}
#endif

	END_COM_METHOD(g_fact, IID_IStream);
}