⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 xfttextrenderer.cpp

📁 khtml在gtk上的移植版本
💻 CPP
字号:
/* * Copyright (c) 2004 Nokia. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the * distribution. * * Neither the name of Nokia nor the names of its contributors may be * used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. */#include <assert.h>#include <glib.h>#include <gdk/gdkx.h>#include <gdk/gdk.h>#include <fontconfig/fontconfig.h>#include <X11/Xft/Xft.h>#include <X11/Xlib.h>#include "XftTextRenderer.h"#include "XftTextRendererFactory.h"#include "GdkXftContext.h"#define USE_XFT_DRAWRECTstaticUniChar*dupCharsAndRemoveLF(const UniChar* chars, unsigned int length){    assert(length>0);    assert(chars);    UniChar uc_space(' ');    UniChar* dup = new UniChar[length];    const gunichar2* uc_chars = reinterpret_cast<const gunichar2*>(chars);    for(unsigned int i = 0; i < length; i++) {	if (g_unichar_isspace(uc_chars[i]))	    dup[i] = uc_space;	else	    dup[i] = chars[i];    }    return dup;}// notice: this code is assuming that there is no consecutive spaces// [a,b[ range of chars that make a word, ie "abcd dabcd" would produce (0,4) (5,9) typedef struct _WordRange { unsigned short start; unsigned short stop; } WordRange;staticint scanRunForWords(const WebCoreTextRun* run, int from, WordRange* words, int maxWords, int* nWords, int* totWords){    assert(run);    assert(run->from <= run->to);    assert(nWords);    *nWords = 0;    int tot = 0;    if (run->from == run->to)	return from;    const gunichar2* ucs = reinterpret_cast<const gunichar2*>(run->characters);    // scan until end of run or we run out of word slots    int start, stop;    start = from;    while (start < run->to && tot < maxWords) {	// move the stop to point at the last char before space or at the end of the buffer	// stop == start if there's consecutive spaces ('words of lenght == 0')	for (stop = start; stop < run->to && !g_unichar_isspace(*(ucs + stop)); stop++) /* empty */; 	words[tot].start = start;	words[tot].stop = stop;	++tot;	start = stop + 1; // skip the space 	++(*nWords);    }        if (totWords) {	*totWords = tot;	if (start < run->to) { 	    // ran out of words before finished scanning	    // scan the total amount of words	    for(int pos = start; pos < run->to; pos++) {		if (g_unichar_isspace(*(ucs + pos))) 		    ++(*totWords);	    }	}    }    return start;}inline staticvoid getXRenderColorFromGdkColor(const GdkColor* gdkc, XRenderColor* xrc){    xrc->red = gdkc->red;    xrc->blue = gdkc->blue;    xrc->green = gdkc->green;    xrc->alpha = 0xffff;}XftTextRenderer::XftTextRenderer(XftTextRendererFactory* aowner, XftNSFont *afont)    : owner(aowner)    , gdkxoff(0)    , gdkyoff(0)    , xftdraw(0)    , font(afont)    , xclip(0){      font->retain();    ascent = font->ascent;    descent = font->descent;    lineSpacing = font->lineSpacing;    xHeight = font->xHeight;    /** fixme: figure out how to propagate this */    xdisplay = GDK_DISPLAY();}XftTextRenderer::~XftTextRenderer(){    if (xclip)	XDestroyRegion(xclip);    font->release();    if (owner) 	owner->rendererDeleted(this);}void XftTextRenderer::setContext(CGContextRef acontext){    GdkXftContext* context = static_cast<GdkXftContext*>(acontext);    assert(context);    xftdraw = context->xftDraw();    xvisual = context->XVisual();    xcmap = context->XColormap();    gdkxoff = gdkyoff = 0;    context->xftTranslate(&gdkxoff, &gdkyoff);}float XftTextRenderer::measureRange(const WebCoreTextRun *run, const WebCoreTextStyle *style, int from, int to, float* widths){    XGlyphInfo extents;    if (style->letterSpacing == 0 && !widths) {	XftTextExtents16( xdisplay,			  font->xftFont,			  reinterpret_cast<const XftChar16*>(run->characters + from),			  to - from,			  &extents);	return extents.xOff;    }    float w, totalLen = 0.0f;    int i = 0;    while (from < to) {	XftTextExtents16(xdisplay,			 font->xftFont,			 reinterpret_cast<const XftChar16*>(run->characters + from),			 1,			 &extents);	w = extents.xOff + style->letterSpacing;	totalLen += w;	if (widths)	    widths[i++] = w;	++from;    }        return totalLen;}float XftTextRenderer::drawRange(const WebCoreTextRun *run, const WebCoreTextStyle *style, int from, int to, int x, int y, const XftColor* color, bool shouldMeasure){    int width = 0;    XGlyphInfo extents;    if (style->letterSpacing) {	while (from<to) {	    XftTextExtents16(xdisplay, 			     font->xftFont,			     reinterpret_cast<const XftChar16*>(run->characters + from),     			     1,			     &extents);	    XftDrawString16(xftdraw,			    color,			    font->xftFont,			    x,			    y,			    reinterpret_cast<const XftChar16*>(run->characters + from),			    1);	    x += extents.xOff + style->letterSpacing;	    ++from;	    width += extents.xOff + style->letterSpacing;	}	return width;    } else {	if (shouldMeasure) {	    XftTextExtents16(xdisplay, 			     font->xftFont,			     reinterpret_cast<const XftChar16*>(run->characters + from),			     to - from,			     			     &extents);	    width += extents.xOff;	}	XftDrawString16(xftdraw,			color,			font->xftFont,			x,			y,			reinterpret_cast<const XftChar16*>(run->characters + from),			to - from);    }    return width;}float XftTextRenderer::floatWidthForRun(const WebCoreTextRun *run,					const WebCoreTextStyle *style,					float *widths){    assert(run);    assert(style);    assert(style->families);        if (run->length == 0)	return 0.0f;    const int wordBufSz = 10;	// size of scan buffer    WordRange words[wordBufSz]; // scan buffer    int nWords;			// number of words in scan buffer    int totWords = 0;		// total word count    // needs always totWords because wordSpacing is applied only to spaces in the middle, not    // for the last word. Is this correct practice?    scanRunForWords(run, run->from, words, wordBufSz, &nWords, &totWords);    // run->from == run->to == 0    if (totWords == 0)	return 0.0f;          const float wordPadding = (totWords>1) ? style->padding / (totWords-1) : 0.0f; 	// padding between words    float totalWidth = 0.0f;//    float wordWidth = 0.0f;    int wordsMeasured = 0;    int wordIndex;    int whiteScanFrom = run->from;    totalWidth += (words[0].start - run->from) * (font->spaceWidth+style->wordSpacing + style->letterSpacing);    while (1) {	// iterate over scan buffer	for (wordIndex = 0; wordIndex < nWords; wordIndex++) {	    totalWidth += (words[wordIndex].start - whiteScanFrom) * (font->spaceWidth+style->wordSpacing+style->letterSpacing);			    totalWidth += measureRange(run, style, words[wordIndex].start, words[wordIndex].stop, widths);	    if (wordsMeasured > 0) {  		// has space-char after the word		if (widths) {		    widths[words[wordIndex].stop] = wordPadding + font->spaceWidth + style->wordSpacing + style->letterSpacing;		}	    }	    whiteScanFrom = words[wordIndex].stop;	    ++wordsMeasured;	}	if (nWords > 0 && words[nWords-1].stop+1 < run->to) {            // update scan buffer (will happen if number of spaces > wordBufSz)	    scanRunForWords(run, words[nWords-1].stop+1, words, wordBufSz, &nWords, NULL); 		} else 	    break;    }    totalWidth += (run->to - words[wordIndex-1].stop) * (font->spaceWidth+style->wordSpacing+style->letterSpacing);    return totalWidth + style->padding;}// static// int indexToSeparator(const XftChar16* str, unsigned int length)// {//     const gunichar2* uc_chars = reinterpret_cast<const gunichar2*>(str);//     unsigned int i;//     for( i = 0; i < length; i++) {// 	if (g_unichar_isspace(*uc_chars))// 	    break;// 	uc_chars++;//     }//     return i;// }void XftTextRenderer::drawRun(const WebCoreTextRun *run, const WebCoreTextStyle *style, int x, int y){    assert(run);    assert(style);    assert(style->families);        if (run->length == 0) 	return;    XRenderColor xrc;    XftColor c;      getXRenderColorFromGdkColor(&style->textColor, &xrc);    XftColorAllocValue(xdisplay,		       xvisual,		       xcmap,		       &xrc,		       &c);    x -=  gdkxoff;    y -=  gdkyoff;    const int wordBufSz = 10;	// size of scan buffer    WordRange words[wordBufSz]; // scan buffer    int nWords;			// number of words in scan buffer    int totWords = 0;		// total word count    // needs always totWords because wordSpacing is applied only to spaces in the middle, not    // for the last word. Is this correct practice?    scanRunForWords(run, run->from, words, wordBufSz, &nWords, &totWords);    if (totWords == 0) 	return;    float wordPadding =  style->padding / totWords;    float wordWidth = 0.0f;    int wordsDrawn = 0;    int wordIndex;    while (1) {	// iterate over scan buffer	for (wordIndex = 0; wordIndex < nWords; wordIndex++) {	    wordWidth = drawRange(run, style, words[wordIndex].start, words[wordIndex].stop, x, y, &c, true);	    // not last word	    wordWidth += wordPadding;	    wordWidth += font->spaceWidth + style->wordSpacing;	    x += (int)wordWidth;	    ++wordsDrawn;	} 	if (nWords > 0 && words[nWords-1].stop+1 < run->to) {            // update scan buffer (will happen if number of spaces > wordBufSz)	    scanRunForWords(run, words[nWords-1].stop+1, words, wordBufSz, &nWords, NULL); 		} else 	    break;    }    XftColorFree(xdisplay,		 xvisual,		 xcmap,		 &c);        if (style->rtl){	g_warning("RTL painting not implemented"); 	// FIXME:: Handle right-to-left text    }}void XftTextRenderer::drawHighlightForRun(const WebCoreTextRun *run, const WebCoreTextStyle *style, const WebCoreTextGeometry *geom){    assert(run);    assert(style);    assert(style->families);    if (run->length == 0) 	return ;    int x=0, y=0, w=0, h=0;    XGlyphInfo extents;    UniChar* uchars = dupCharsAndRemoveLF(run->characters, run->length);    x = (int)geom->selectionMinX;    y = (int)geom->y;    if (run->from > 0) {	XftTextExtents16( xdisplay, 			  font->xftFont,			  reinterpret_cast<const XftChar16*>(uchars),			  run->from,			  &extents);		x += extents.xOff /* + style->padding*/; // xOff == offset where the next char starts    }    XftTextExtents16( xdisplay, 		      font->xftFont,		      reinterpret_cast<const XftChar16*>(uchars + run->from),		      run->to - run->from,		      &extents);    w = (int)extents.width;    h = (int)geom->selectionHeight;    drawRect(x,y,w,h, &style->textColor);    delete[] uchars;}void XftTextRenderer::drawLineForCharacters(int x, int y, float yOffset, int width, GdkColor* color){}// selection point checkint XftTextRenderer::pointToOffset(const WebCoreTextRun *run, const WebCoreTextStyle *style, int x, bool reversed, bool includePartialGlyphs){    assert(run);    assert(style);    assert(style->families);    if (run->length == 0) 	return 0;    XGlyphInfo extents;    UniChar* uchars = dupCharsAndRemoveLF(run->characters, run->length);    // binary search for offset in string for pixel position x    int start, end;    start = run->from;    end = run->to;    int xpos;    int len_mid;        while (start < end) {	len_mid = ((end - start)+1) / 2;	XftTextExtents16(xdisplay,			 font->xftFont,			 reinterpret_cast<const XftChar16*>(uchars + start),			 len_mid,			 &extents);		xpos = extents.xOff;	if (xpos < x) {	    start += len_mid;	    x -= xpos;	} else if (xpos > x) {	    end -= len_mid;	}else {	    start += len_mid;	    break;	}    }    delete [] uchars;    return start - run->from;}void XftTextRenderer::drawRect(int x, int y, int w, int h, const GdkColor* color){    #if defined(USE_XFT_DRAWRECT)    g_warning("(%d,%d,%d,%d)", x,y,w,h);    XftColor xft_c;    XRenderColor xrender_c;        getXRenderColorFromGdkColor(color, &xrender_c);        XftColorAllocValue(xdisplay,		       xvisual,		       xcmap,		       &xrender_c,		       &xft_c);    x -= gdkxoff;    y -= gdkyoff;    XftDrawRect(xftdraw, &xft_c, x, y, w, h);        XftColorFree(xdisplay,		 xvisual,		 xcmap,		 &xft_c);#else    gdk_gc_set_rgb_fg_color(gdkgc, const_cast<GdkColor*>(color));    x -= gdkxoff;    y -= gdkyoff;    gdk_gc_set_fill (gdkgc, GDK_SOLID);    gdk_draw_rectangle(gdkdrawable, gdkgc, TRUE, x, y, w, h);#endif}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -