зеркало из https://github.com/mozilla/gecko-dev.git
r=blizzard, sr=kin@netscape.com, a=asa for drivers XLIB only - Checkin for timecop@network.email.ne.jp - adding gc-cache to xlib port
This commit is contained in:
Родитель
2cbbc0ecad
Коммит
6ecd046893
|
@ -0,0 +1,226 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
* vim:ts=2:et:sw=2:
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public
|
||||
* License Version 1.1 (the "License"); you may not use this file
|
||||
* except in compliance with the License. You may obtain a copy of
|
||||
* the License at http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS
|
||||
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
|
||||
* implied. See the License for the specific language governing
|
||||
* rights and limitations under the License.
|
||||
*
|
||||
* The Original Code is mozilla.org code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape
|
||||
* Communications Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 2001 Netscape Communications Corporation. All
|
||||
* Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Stuart Parmenter <pavlov@netscape.com>
|
||||
* Syd Logan <syd@netscape.com>
|
||||
* Xlibified by tim copperfield <timecop@japan.co.jp>
|
||||
*/
|
||||
|
||||
#include "drawers.h"
|
||||
|
||||
#ifdef HAVE_XIE
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <X11/extensions/XIElib.h>
|
||||
#include "prenv.h"
|
||||
/* why do I need this define? */
|
||||
#define USE_MOZILLA_TYPES
|
||||
#include "xlibrgb.h"
|
||||
|
||||
/* #define DEBUG_XIE 1 */
|
||||
static PRBool useXIE = PR_TRUE;
|
||||
static PRBool inited = PR_FALSE;
|
||||
static XiePhotospace gPhotospace;
|
||||
static XiePhotoElement *photoElement;
|
||||
|
||||
static void
|
||||
DoFlo(Display *display,
|
||||
Drawable aDest,
|
||||
GC aGC,
|
||||
Drawable aSrc,
|
||||
PRInt32 aSrcWidth,
|
||||
PRInt32 aSrcHeight,
|
||||
PRInt32 aSX,
|
||||
PRInt32 aSY,
|
||||
PRInt32 aSWidth,
|
||||
PRInt32 aSHeight,
|
||||
PRInt32 aDX,
|
||||
PRInt32 aDY,
|
||||
PRInt32 aDWidth,
|
||||
PRInt32 aDHeight)
|
||||
{
|
||||
XieExtensionInfo *info;
|
||||
float coeffs[6];
|
||||
XieConstant constant;
|
||||
XiePhototag idx = 0, src;
|
||||
|
||||
/* create the pretty flo graph */
|
||||
|
||||
|
||||
/* import */
|
||||
XieFloImportDrawable(&photoElement[idx], aSrc,
|
||||
aSX, aSY, aSWidth, aSHeight,
|
||||
0, PR_FALSE);
|
||||
++idx;
|
||||
src = idx;
|
||||
|
||||
/* do the scaling stuff */
|
||||
coeffs[0] = (float)aSrcWidth / (float)aDWidth;
|
||||
coeffs[1] = 0.0;
|
||||
coeffs[2] = 0.0;
|
||||
coeffs[3] = (float)aSrcHeight / (float)aDHeight;
|
||||
coeffs[4] = 0.0;
|
||||
coeffs[5] = 0.0;
|
||||
|
||||
constant[0] = 128.0;
|
||||
constant[1] = 128.0;
|
||||
constant[2] = 128.0;
|
||||
|
||||
XieFloGeometry(&photoElement[idx], src, aDWidth, aDHeight,
|
||||
coeffs,
|
||||
constant,
|
||||
0x07,
|
||||
xieValGeomNearestNeighbor,
|
||||
NULL);
|
||||
++idx;
|
||||
|
||||
/* export */
|
||||
XieFloExportDrawable(&photoElement[idx], idx, aDest, aGC,
|
||||
(aDX - aSX),
|
||||
(aDY - aSY));
|
||||
++idx;
|
||||
|
||||
|
||||
/* do the scale thing baby */
|
||||
XieExecuteImmediate(display, gPhotospace, 1, PR_FALSE, photoElement, idx);
|
||||
|
||||
|
||||
/*
|
||||
XieFreePhotofloGraph(photoElement, 3);
|
||||
*/
|
||||
}
|
||||
|
||||
PRBool
|
||||
DrawScaledImageXIE(Display *display,
|
||||
Drawable aDest,
|
||||
GC aGC,
|
||||
Drawable aSrc,
|
||||
Drawable aSrcMask,
|
||||
PRInt32 aSrcWidth,
|
||||
PRInt32 aSrcHeight,
|
||||
PRInt32 aSX,
|
||||
PRInt32 aSY,
|
||||
PRInt32 aSWidth,
|
||||
PRInt32 aSHeight,
|
||||
PRInt32 aDX,
|
||||
PRInt32 aDY,
|
||||
PRInt32 aDWidth,
|
||||
PRInt32 aDHeight)
|
||||
{
|
||||
Pixmap alphaMask = 0;
|
||||
GC gc = 0;
|
||||
|
||||
#ifdef DEBUG_XIE
|
||||
printf("DrawScaledImageXIE\n");
|
||||
#endif
|
||||
|
||||
if (!useXIE) {
|
||||
#ifdef DEBUG_XIE
|
||||
fprintf(stderr, "useXIE is false.\n");
|
||||
#endif
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
||||
if (!inited) {
|
||||
XieExtensionInfo *info;
|
||||
|
||||
if (useXIE) {
|
||||
char *text = PR_GetEnv("MOZ_DISABLE_XIE");
|
||||
if (text) {
|
||||
#ifdef DEBUG_XIE
|
||||
fprintf(stderr, "MOZ_DISABLE_XIE set, disabling use of XIE.\n");
|
||||
#endif
|
||||
useXIE = PR_FALSE;
|
||||
return PR_FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
if (!XieInitialize(display, &info)) {
|
||||
useXIE = PR_FALSE;
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
||||
inited = PR_TRUE;
|
||||
|
||||
/* create the photospace (we only need to do this once) */
|
||||
gPhotospace = XieCreatePhotospace(display);
|
||||
|
||||
photoElement = XieAllocatePhotofloGraph(3);
|
||||
|
||||
/* XXX we want to destroy this at shutdown
|
||||
XieDestroyPhotospace(display, photospace);
|
||||
*/
|
||||
}
|
||||
|
||||
if (aSrcMask) {
|
||||
GC tmpgc;
|
||||
#ifdef DEBUG_XIE
|
||||
fprintf(stderr, "DrawScaledImageXIE with alpha mask\n");
|
||||
#endif
|
||||
alphaMask = XCreatePixmap(display,
|
||||
DefaultRootWindow(xlib_rgb_get_display()),
|
||||
aDWidth, aDHeight, 1);
|
||||
|
||||
/* we need to make a worthless depth 1 GC to do the flow
|
||||
* because GC's can only be used with the same depth drawables */
|
||||
tmpgc = XCreateGC(display, alphaMask, 0, NULL);
|
||||
|
||||
/* run the flo on the alpha mask to get a scaled alpha mask */
|
||||
DoFlo(display, alphaMask, tmpgc, aSrcMask,
|
||||
aSrcWidth, aSrcHeight,
|
||||
aSX, aSY, aSWidth, aSHeight,
|
||||
aDX, aDY, aDWidth, aDHeight);
|
||||
|
||||
/* get rid of the worthless depth 1 gc */
|
||||
XFreeGC(display, tmpgc);
|
||||
|
||||
/* the real GC needs to be created on aDest since that's the depth
|
||||
* we are targeting */
|
||||
gc = XCreateGC(display, aDest, 0, NULL);
|
||||
XCopyGC(display, aGC, GCFunction, gc);
|
||||
|
||||
/* there is a bug here. The image won't display unless it's at the
|
||||
* very top of the page. Something to do with clip mask offset, though
|
||||
* I can't really figure it out. If this is a bug, it should be present
|
||||
* in the GTK version as well. */
|
||||
|
||||
/* set clip mask + clip origin */
|
||||
XSetClipMask(display, gc, alphaMask);
|
||||
XSetClipOrigin(display, gc, aDX + aSX, aDY + aSY);
|
||||
}
|
||||
|
||||
/* run the flo on the image to get a the scaled image
|
||||
* we can't destroy the GC from gc cache, so we do the ? thing,
|
||||
* gc = our copied GC, aGC = given GC */
|
||||
DoFlo(display, aDest, gc ? gc : aGC, aSrc,
|
||||
aSrcWidth, aSrcHeight,
|
||||
aSX, aSY, aSWidth, aSHeight,
|
||||
aDX, aDY, aDWidth, aDHeight);
|
||||
|
||||
if (gc)
|
||||
XFreeGC(display, gc);
|
||||
if (alphaMask)
|
||||
XFreePixmap(display, alphaMask);
|
||||
|
||||
return PR_TRUE;
|
||||
}
|
||||
#endif
|
|
@ -0,0 +1,84 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
* vim:ts=2:et:sw=2:
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public
|
||||
* License Version 1.1 (the "License"); you may not use this file
|
||||
* except in compliance with the License. You may obtain a copy of
|
||||
* the License at http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS
|
||||
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
|
||||
* implied. See the License for the specific language governing
|
||||
* rights and limitations under the License.
|
||||
*
|
||||
* The Original Code is mozilla.org code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape
|
||||
* Communications Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 2001 Netscape Communications Corporation. All
|
||||
* Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Stuart Parmenter <pavlov@netscape.com>
|
||||
*/
|
||||
|
||||
#include "prtypes.h"
|
||||
#include <X11/Xlib.h>
|
||||
|
||||
PR_BEGIN_EXTERN_C
|
||||
|
||||
#ifdef HAVE_XIE
|
||||
PRBool
|
||||
DrawScaledImageXIE(Display *display,
|
||||
Drawable aDest,
|
||||
GC aGC,
|
||||
Drawable aSrc,
|
||||
Drawable aSrcMask,
|
||||
PRInt32 aSrcWidth,
|
||||
PRInt32 aSrcHeight,
|
||||
PRInt32 aSX,
|
||||
PRInt32 aSY,
|
||||
PRInt32 aSWidth,
|
||||
PRInt32 aSHeight,
|
||||
PRInt32 aDX,
|
||||
PRInt32 aDY,
|
||||
PRInt32 aDWidth,
|
||||
PRInt32 aDHeight);
|
||||
#endif
|
||||
|
||||
PRBool
|
||||
DrawScaledImageNN(Display *display,
|
||||
Drawable aDest,
|
||||
GC aGC,
|
||||
Drawable aSrc,
|
||||
Drawable aSrcMask,
|
||||
PRInt32 aSrcWidth,
|
||||
PRInt32 aSrcHeight,
|
||||
PRInt32 aSX,
|
||||
PRInt32 aSY,
|
||||
PRInt32 aSWidth,
|
||||
PRInt32 aSHeight,
|
||||
PRInt32 aDX,
|
||||
PRInt32 aDY,
|
||||
PRInt32 aDWidth,
|
||||
PRInt32 aDHeight);
|
||||
|
||||
PRBool
|
||||
DrawScaledImageBitsNN(Display *display,
|
||||
Drawable aDest,
|
||||
GC aGC,
|
||||
const PRUint8 *aSrc,
|
||||
PRInt32 aBytesPerRow,
|
||||
const PRUint8 *aSrcMask,
|
||||
PRInt32 aSrcWidth,
|
||||
PRInt32 aSrcHeight,
|
||||
PRInt32 aSX,
|
||||
PRInt32 aSY,
|
||||
PRInt32 aSWidth,
|
||||
PRInt32 aSHeight,
|
||||
PRInt32 aDX,
|
||||
PRInt32 aDY,
|
||||
PRInt32 aDWidth,
|
||||
PRInt32 aDHeight);
|
||||
|
||||
PR_END_EXTERN_C
|
|
@ -0,0 +1,231 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public
|
||||
* License Version 1.1 (the "License"); you may not use this file
|
||||
* except in compliance with the License. You may obtain a copy of
|
||||
* the License at http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS
|
||||
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
|
||||
* implied. See the License for the specific language governing
|
||||
* rights and limitations under the License.
|
||||
*
|
||||
* The Original Code is the Mozilla browser.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape
|
||||
* Communications Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 1999 Netscape Communications Corporation. All
|
||||
* Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Stuart Parmenter <pavlov@netscape.com>
|
||||
* Mike Shaver <shaver@zeroknowledge.com>
|
||||
* Tomi Leppikangas <Tomi.Leppikangas@oulu.fi>
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include "nsGCCache.h"
|
||||
|
||||
#include <X11/Xlib.h>
|
||||
#include <X11/Xutil.h>
|
||||
|
||||
/* The GC cache is shared among all windows, since it doesn't hog
|
||||
any scarce resources (like colormap entries.) */
|
||||
|
||||
Region nsGCCache::copyRegion = 0;
|
||||
|
||||
nsGCCache::nsGCCache()
|
||||
{
|
||||
PR_INIT_CLIST(&GCCache);
|
||||
PR_INIT_CLIST(&GCFreeList);
|
||||
for (int i = 0; i < GC_CACHE_SIZE; i++) {
|
||||
GCCacheEntry *entry = new GCCacheEntry();
|
||||
entry->gc=NULL;
|
||||
PR_INSERT_LINK(&entry->clist, &GCFreeList);
|
||||
}
|
||||
DEBUG_METER(memset(&GCCacheStats, 0, sizeof(GCCacheStats));)
|
||||
}
|
||||
|
||||
void
|
||||
nsGCCache::move_cache_entry(PRCList *clist)
|
||||
{
|
||||
/* thread on the freelist, at the front */
|
||||
PR_REMOVE_LINK(clist);
|
||||
PR_INSERT_LINK(clist, &GCFreeList);
|
||||
}
|
||||
|
||||
void
|
||||
nsGCCache::free_cache_entry(PRCList *clist)
|
||||
{
|
||||
GCCacheEntry *entry = (GCCacheEntry *)clist;
|
||||
entry->gc->Release();
|
||||
if (entry->clipRegion)
|
||||
::XDestroyRegion(entry->clipRegion);
|
||||
|
||||
/* thread on the freelist, at the front */
|
||||
PR_REMOVE_LINK(clist);
|
||||
memset(entry, 0, sizeof(*entry));
|
||||
PR_INSERT_LINK(clist, &GCFreeList);
|
||||
}
|
||||
|
||||
nsGCCache::~nsGCCache()
|
||||
{
|
||||
PRCList *head;
|
||||
|
||||
ReportStats();
|
||||
|
||||
while (!PR_CLIST_IS_EMPTY(&GCCache)) {
|
||||
head = PR_LIST_HEAD(&GCCache);
|
||||
if (head == &GCCache)
|
||||
break;
|
||||
free_cache_entry(head);
|
||||
}
|
||||
|
||||
while (!PR_CLIST_IS_EMPTY(&GCFreeList)) {
|
||||
head = PR_LIST_HEAD(&GCFreeList);
|
||||
if (head == &GCFreeList)
|
||||
break;
|
||||
PR_REMOVE_LINK(head);
|
||||
delete (GCCacheEntry *)head;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
nsGCCache::ReportStats() {
|
||||
DEBUG_METER(
|
||||
fprintf(stderr, "GC Cache:\n\thits:");
|
||||
int hits = 0;
|
||||
for (int i = 0; i < GC_CACHE_SIZE; i++) {
|
||||
fprintf(stderr, " %4d", GCCacheStats.hits[i]);
|
||||
hits+=GCCacheStats.hits[i];
|
||||
}
|
||||
int total = hits + GCCacheStats.misses;
|
||||
float percent = float(float(hits) / float(total));
|
||||
percent *= 100;
|
||||
fprintf(stderr, "\n\thits: %d, misses: %d, hit percent: %f%%\n",
|
||||
hits, GCCacheStats.misses, percent);
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
nsGCCache::XCopyRegion(Region srca, Region dr_return)
|
||||
{
|
||||
if (!copyRegion) copyRegion = ::XCreateRegion();
|
||||
::XUnionRegion(srca, copyRegion, dr_return);
|
||||
}
|
||||
|
||||
/* Dispose of entries matching the given flags, compressing the GC cache */
|
||||
void nsGCCache::Flush(unsigned long flags)
|
||||
{
|
||||
while (!PR_CLIST_IS_EMPTY(&GCCache)) {
|
||||
PRCList *head = PR_LIST_HEAD(&GCCache);
|
||||
if (head == &GCCache)
|
||||
break;
|
||||
GCCacheEntry *entry = (GCCacheEntry *)head;
|
||||
if (entry->flags & flags)
|
||||
free_cache_entry(head);
|
||||
}
|
||||
}
|
||||
|
||||
xGC *nsGCCache::GetGC(Display *display, Drawable drawable, unsigned long flags, XGCValues *gcv, Region clipRegion)
|
||||
{
|
||||
PRCList *iter;
|
||||
GCCacheEntry *entry;
|
||||
DEBUG_METER(int i = 0;)
|
||||
|
||||
for (iter = PR_LIST_HEAD(&GCCache); iter != &GCCache;
|
||||
iter = PR_NEXT_LINK(iter)) {
|
||||
|
||||
entry = (GCCacheEntry *)iter;
|
||||
if (flags == entry->flags &&
|
||||
!memcmp (gcv, &entry->gcv, sizeof (*gcv))) {
|
||||
/* if there's a clipRegion, we have to match */
|
||||
|
||||
if ((clipRegion && entry->clipRegion &&
|
||||
::XEqualRegion(clipRegion, entry->clipRegion)) ||
|
||||
/* and if there isn't, we can't have one */
|
||||
(!clipRegion && !entry->clipRegion)) {
|
||||
|
||||
/* move to the front of the list, if needed */
|
||||
if (iter != PR_LIST_HEAD(&GCCache)) {
|
||||
PR_REMOVE_LINK(iter);
|
||||
PR_INSERT_LINK(iter, &GCCache);
|
||||
}
|
||||
DEBUG_METER(GCCacheStats.hits[i]++;)
|
||||
|
||||
entry->gc->AddRef();
|
||||
return entry->gc;
|
||||
}
|
||||
}
|
||||
DEBUG_METER(++i;)
|
||||
}
|
||||
|
||||
/* might need to forcibly free the LRU cache entry */
|
||||
if (PR_CLIST_IS_EMPTY(&GCFreeList)) {
|
||||
DEBUG_METER(GCCacheStats.reclaim++);
|
||||
move_cache_entry(PR_LIST_TAIL(&GCCache));
|
||||
}
|
||||
|
||||
DEBUG_METER(GCCacheStats.misses++;)
|
||||
|
||||
iter = PR_LIST_HEAD(&GCFreeList);
|
||||
PR_REMOVE_LINK(iter);
|
||||
PR_INSERT_LINK(iter, &GCCache);
|
||||
entry = (GCCacheEntry *)iter;
|
||||
|
||||
if (!entry->gc) {
|
||||
// No old GC, greate new
|
||||
entry->gc = new xGC(display, drawable, flags, gcv);
|
||||
entry->gc->AddRef(); // addref the newly created xGC
|
||||
entry->flags = flags;
|
||||
entry->gcv = *gcv;
|
||||
entry->clipRegion = NULL;
|
||||
//printf("creating new gc=%X\n",entry->gc);
|
||||
}
|
||||
else if (entry->gc->mRefCnt > 0) {
|
||||
// Old GC still in use, create new
|
||||
entry->gc->Release();
|
||||
entry->gc = new xGC(display, drawable, flags, gcv);
|
||||
entry->gc->AddRef(); // addref the newly created xGC
|
||||
entry->flags = flags;
|
||||
entry->gcv = *gcv;
|
||||
entry->clipRegion = NULL;
|
||||
//printf("creating new (use)gc=%X\n",entry->gc);
|
||||
}
|
||||
else {
|
||||
ReuseGC(entry, flags, gcv);
|
||||
}
|
||||
|
||||
if (clipRegion) {
|
||||
entry->clipRegion = ::XCreateRegion();
|
||||
XCopyRegion(clipRegion, entry->clipRegion);
|
||||
if (entry->clipRegion)
|
||||
::XSetRegion(display, entry->gc->mGC, entry->clipRegion);
|
||||
/* XXX what if it fails? */
|
||||
}
|
||||
|
||||
entry->gc->AddRef();
|
||||
return entry->gc;
|
||||
}
|
||||
|
||||
void nsGCCache::ReuseGC(GCCacheEntry *entry, unsigned long flags, XGCValues *gcv)
|
||||
{
|
||||
// We have old GC, reuse it and check what
|
||||
// we have to change
|
||||
|
||||
if (entry->clipRegion) {
|
||||
// set it to none here and then set the clip region with
|
||||
// gdk_gc_set_clip_region in GetGC()
|
||||
gcv->clip_mask = None;
|
||||
flags |= GCClipMask;
|
||||
::XDestroyRegion(entry->clipRegion);
|
||||
entry->clipRegion = NULL;
|
||||
}
|
||||
|
||||
if (flags != 0) {
|
||||
::XChangeGC(entry->gc->mDisplay, entry->gc->mGC,
|
||||
flags, gcv);
|
||||
}
|
||||
entry->flags = flags; entry->gcv = *gcv;
|
||||
}
|
|
@ -0,0 +1,131 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public
|
||||
* License Version 1.1 (the "License"); you may not use this file
|
||||
* except in compliance with the License. You may obtain a copy of
|
||||
* the License at http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS
|
||||
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
|
||||
* implied. See the License for the specific language governing
|
||||
* rights and limitations under the License.
|
||||
*
|
||||
* The Original Code is the Mozilla browser.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape
|
||||
* Communications Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 1999 Netscape Communications Corporation. All
|
||||
* Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Stuart Parmenter <pavlov@netscape.com>
|
||||
* Mike Shaver <shaver@zeroknowledge.com>
|
||||
*/
|
||||
|
||||
|
||||
#ifndef nsGCCache_h___
|
||||
#define nsGCCache_h___
|
||||
|
||||
#include <X11/Xlib.h>
|
||||
#include <X11/Xutil.h>
|
||||
|
||||
#include <string.h>
|
||||
#include "nscore.h"
|
||||
#include "prclist.h"
|
||||
#include <stdlib.h>
|
||||
|
||||
#define countof(x) ((int)(sizeof(x) / sizeof (*x)))
|
||||
#define GC_CACHE_SIZE 10
|
||||
|
||||
#define DEBUG 1
|
||||
|
||||
#ifdef DEBUG
|
||||
#define DEBUG_METER(x) x
|
||||
#else
|
||||
#define DEBUG_METER(x)
|
||||
#endif
|
||||
|
||||
class nsGCCache;
|
||||
|
||||
class xGC {
|
||||
friend class nsGCCache;
|
||||
|
||||
public:
|
||||
xGC(Display *display, Drawable d, unsigned long valuemask, XGCValues *values)
|
||||
{
|
||||
mRefCnt = 0;
|
||||
mDisplay = display;
|
||||
mGC = ::XCreateGC(display, d, valuemask, values);
|
||||
}
|
||||
|
||||
virtual ~xGC() {
|
||||
::XFreeGC(mDisplay, mGC);
|
||||
}
|
||||
|
||||
PRInt32 AddRef(void) {
|
||||
if(mRefCnt>100) abort();
|
||||
NS_PRECONDITION(PRInt32(mRefCnt) >= 0, "illegal refcnt");
|
||||
++mRefCnt;
|
||||
return mRefCnt;
|
||||
}
|
||||
PRInt32 Release(void) {
|
||||
NS_PRECONDITION(0 != mRefCnt, "dup release");
|
||||
--mRefCnt;
|
||||
if (mRefCnt == 0) {
|
||||
mRefCnt = 1; /* stabilize */
|
||||
delete this;
|
||||
return 0;
|
||||
}
|
||||
return mRefCnt;
|
||||
}
|
||||
|
||||
//operator GC() { return mGC; }
|
||||
operator const GC() { return (const GC)mGC; }
|
||||
|
||||
private:
|
||||
PRInt32 mRefCnt;
|
||||
Display *mDisplay;
|
||||
GC mGC;
|
||||
};
|
||||
|
||||
|
||||
struct GCCacheEntry
|
||||
{
|
||||
PRCList clist;
|
||||
unsigned long flags;
|
||||
XGCValues gcv;
|
||||
Region clipRegion;
|
||||
xGC *gc;
|
||||
};
|
||||
|
||||
class nsGCCache
|
||||
{
|
||||
public:
|
||||
nsGCCache();
|
||||
virtual ~nsGCCache();
|
||||
|
||||
void Flush(unsigned long flags);
|
||||
|
||||
xGC *GetGC(Display *display, Window window, unsigned long flags, XGCValues *gcv, Region clipRegion);
|
||||
|
||||
private:
|
||||
void ReuseGC(GCCacheEntry *entry, unsigned long flags, XGCValues *gcv);
|
||||
PRCList GCCache;
|
||||
PRCList GCFreeList;
|
||||
void free_cache_entry(PRCList *clist);
|
||||
void move_cache_entry(PRCList *clist);
|
||||
static void XCopyRegion(Region src, Region dr_return);
|
||||
static Region copyRegion;
|
||||
void ReportStats();
|
||||
|
||||
DEBUG_METER(
|
||||
struct {
|
||||
int hits[GC_CACHE_SIZE];
|
||||
int misses;
|
||||
int reclaim;
|
||||
} GCCacheStats;
|
||||
)
|
||||
|
||||
};
|
||||
|
||||
#endif
|
|
@ -0,0 +1,318 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
* vim:ts=2:et:sw=2:
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public
|
||||
* License Version 1.1 (the "License"); you may not use this file
|
||||
* except in compliance with the License. You may obtain a copy of
|
||||
* the License at http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS
|
||||
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
|
||||
* implied. See the License for the specific language governing
|
||||
* rights and limitations under the License.
|
||||
*
|
||||
* The Original Code is mozilla.org code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape
|
||||
* Communications Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 2001 Netscape Communications Corporation. All
|
||||
* Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Syd Logan <syd@netscape.com>
|
||||
* Stuart Parmenter <pavlov@netscape.com>
|
||||
* Xlibified by <timecop@japan.co.jp>
|
||||
*/
|
||||
|
||||
#include "drawers.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "nspr.h"
|
||||
/* why do I need this define? */
|
||||
#define USE_MOZILLA_TYPES
|
||||
#include "xlibrgb.h"
|
||||
|
||||
XImage *
|
||||
NNScaleImage(Display *display, XImage *img,
|
||||
double factorX, double factorY,
|
||||
PRInt32 aSWidth, PRInt32 aSHeight,
|
||||
PRInt32 newWidth, PRInt32 newHeight)
|
||||
{
|
||||
XImage *newImg;
|
||||
PRUint32 pixel;
|
||||
PRInt16 i, j, xsrc, ysrc;
|
||||
PRUint32 size;
|
||||
char *data;
|
||||
|
||||
newImg = XCreateImage(display, DefaultVisual(display, 0),
|
||||
img->depth,
|
||||
img->format,
|
||||
0, 0, newWidth, newHeight,
|
||||
img->bitmap_pad, 0);
|
||||
|
||||
if (!newImg) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
size = newHeight * newImg->bytes_per_line;
|
||||
data = (char *) PR_Malloc(size);
|
||||
newImg->data = data;
|
||||
|
||||
if (!data) {
|
||||
XDestroyImage(newImg);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (factorX == 1) {
|
||||
/* an obvious optimization is to bypass XPutPixel
|
||||
and to memcpy rows in img->data if factorX is 1
|
||||
*/
|
||||
|
||||
char *dptr, *sptr;
|
||||
PRUint32 rowsize;
|
||||
|
||||
dptr = newImg->data;
|
||||
rowsize = img->bytes_per_line;
|
||||
for (i = 0; i < newHeight; i++) {
|
||||
ysrc = (PRInt16) (i * factorY);
|
||||
sptr = img->data + ysrc * rowsize;
|
||||
memcpy(dptr, sptr, PR_MIN(rowsize, newImg->bytes_per_line));
|
||||
dptr += newImg->bytes_per_line;
|
||||
}
|
||||
} else {
|
||||
for (i = 0; i < newWidth; i++) {
|
||||
xsrc = (PRInt16) (i * factorX);
|
||||
for (j = 0; j < newHeight; j++) {
|
||||
ysrc = (PRInt16) (j * factorY);
|
||||
pixel = XGetPixel(img, xsrc, ysrc);
|
||||
XPutPixel(newImg, i, j, pixel);
|
||||
}
|
||||
}
|
||||
}
|
||||
return newImg;
|
||||
}
|
||||
|
||||
|
||||
static PRBool
|
||||
DoScale(Display *aDisplay,
|
||||
Drawable aDest,
|
||||
GC aGC,
|
||||
Drawable aSrc,
|
||||
PRInt32 aSrcWidth,
|
||||
PRInt32 aSrcHeight,
|
||||
PRInt32 aSX,
|
||||
PRInt32 aSY,
|
||||
PRInt32 aSWidth,
|
||||
PRInt32 aSHeight,
|
||||
PRInt32 aDX,
|
||||
PRInt32 aDY,
|
||||
PRInt32 aDWidth,
|
||||
PRInt32 aDHeight)
|
||||
{
|
||||
XImage *srcImg = (XImage*)NULL;
|
||||
XImage *dstImg = (XImage*)NULL;
|
||||
|
||||
double factorX = (double)aSrcWidth / (double)aDWidth;
|
||||
double factorY = (double)aSrcHeight / (double)aDHeight;
|
||||
|
||||
srcImg = XGetImage(aDisplay, aSrc,
|
||||
aSX, aSY, aSrcWidth, aSrcHeight,
|
||||
AllPlanes, ZPixmap);
|
||||
|
||||
if (!srcImg)
|
||||
return PR_FALSE;
|
||||
|
||||
dstImg = NNScaleImage(aDisplay, srcImg, factorX, factorY,
|
||||
aSWidth, aSHeight,
|
||||
aDWidth, aDHeight);
|
||||
|
||||
XDestroyImage(srcImg);
|
||||
srcImg = (XImage*)NULL;
|
||||
|
||||
if (!dstImg)
|
||||
return PR_FALSE;
|
||||
|
||||
XPutImage(aDisplay, aDest, aGC, dstImg,
|
||||
0, 0,
|
||||
aDX, aDY,
|
||||
aDWidth, aDHeight);
|
||||
|
||||
PR_Free(dstImg->data); /* we allocated data, don't let Xlib free */
|
||||
dstImg->data = (char *) NULL; /* setting NULL is important!! */
|
||||
|
||||
XDestroyImage(dstImg);
|
||||
|
||||
return PR_TRUE;
|
||||
}
|
||||
|
||||
PRBool
|
||||
DrawScaledImageNN(Display *display,
|
||||
Drawable aDest,
|
||||
GC aGC,
|
||||
Drawable aSrc,
|
||||
Drawable aSrcMask,
|
||||
PRInt32 aSrcWidth,
|
||||
PRInt32 aSrcHeight,
|
||||
PRInt32 aSX,
|
||||
PRInt32 aSY,
|
||||
PRInt32 aSWidth,
|
||||
PRInt32 aSHeight,
|
||||
PRInt32 aDX,
|
||||
PRInt32 aDY,
|
||||
PRInt32 aDWidth,
|
||||
PRInt32 aDHeight)
|
||||
{
|
||||
Pixmap alphaMask = 0;
|
||||
GC gc = 0;
|
||||
|
||||
if (aSrcMask) {
|
||||
GC tmpgc;
|
||||
|
||||
alphaMask = XCreatePixmap(display,
|
||||
DefaultRootWindow(display), aDWidth, aDHeight, 1);
|
||||
|
||||
tmpgc = XCreateGC(display, alphaMask, 0, NULL);
|
||||
|
||||
DoScale(display,
|
||||
alphaMask, /* dest */
|
||||
tmpgc,
|
||||
aSrcMask, /* src */
|
||||
aSrcWidth, aSrcHeight,
|
||||
aSX, aSY,
|
||||
aSWidth, aSHeight,
|
||||
aDX, aDY,
|
||||
aDWidth, aDHeight);
|
||||
|
||||
XFreeGC(display, tmpgc);
|
||||
|
||||
gc = XCreateGC(display, aDest, 0, NULL);
|
||||
XCopyGC(display, aGC, GCFunction, gc);
|
||||
|
||||
XSetClipMask(display, gc, alphaMask);
|
||||
XSetClipOrigin(display, gc, 0, 0);
|
||||
}
|
||||
|
||||
DoScale(display,
|
||||
aDest,
|
||||
gc ? gc : aGC,
|
||||
aSrc,
|
||||
aSrcWidth, aSrcHeight,
|
||||
aSX, aSY,
|
||||
aSWidth, aSHeight,
|
||||
aDX, aDY,
|
||||
aDWidth, aDHeight);
|
||||
|
||||
if (gc)
|
||||
XFreeGC(display, gc);
|
||||
if (alphaMask)
|
||||
XFreePixmap(display, alphaMask);
|
||||
|
||||
return PR_TRUE;
|
||||
}
|
||||
|
||||
#define SCALE_SHIFT 16
|
||||
|
||||
static void
|
||||
pixops_scale_nearest (unsigned char *dest_buf,
|
||||
int render_x0,
|
||||
int render_y0,
|
||||
int render_x1,
|
||||
int render_y1,
|
||||
int dest_rowstride,
|
||||
int dest_channels,
|
||||
const unsigned char *src_buf,
|
||||
int src_width,
|
||||
int src_height,
|
||||
int src_rowstride,
|
||||
int src_channels,
|
||||
double scale_x,
|
||||
double scale_y)
|
||||
{
|
||||
int i, j;
|
||||
int x;
|
||||
int x_step = (1 << SCALE_SHIFT) / scale_x;
|
||||
int y_step = (1 << SCALE_SHIFT) / scale_y;
|
||||
|
||||
printf("%f,%f\n", scale_x, scale_y);
|
||||
|
||||
PR_ASSERT(src_channels == dest_channels);
|
||||
|
||||
for (i = 0; i < (render_y1 - render_y0); i++) {
|
||||
const unsigned char *src = src_buf + (((i + render_y0) * y_step + y_step / 2) >> SCALE_SHIFT) * src_rowstride;
|
||||
unsigned char *dest = dest_buf + i * dest_rowstride;
|
||||
|
||||
x = render_x0 * x_step + x_step / 2;
|
||||
|
||||
for (j=0; j < (render_x1 - render_x0); j++) {
|
||||
const unsigned char *p = src + (x >> SCALE_SHIFT) * src_channels;
|
||||
|
||||
dest[0] = p[0];
|
||||
dest[1] = p[1];
|
||||
dest[2] = p[2];
|
||||
|
||||
dest += dest_channels;
|
||||
x += x_step;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
PRBool
|
||||
DrawScaledImageBitsNN(Display *display,
|
||||
Drawable aDest,
|
||||
GC aGC,
|
||||
const PRUint8 *aSrc,
|
||||
PRInt32 aBytesPerRow,
|
||||
const PRUint8 *aSrcMask,
|
||||
PRInt32 aSrcWidth,
|
||||
PRInt32 aSrcHeight,
|
||||
PRInt32 aSX,
|
||||
PRInt32 aSY,
|
||||
PRInt32 aSWidth,
|
||||
PRInt32 aSHeight,
|
||||
PRInt32 aDX,
|
||||
PRInt32 aDY,
|
||||
PRInt32 aDWidth,
|
||||
PRInt32 aDHeight)
|
||||
{
|
||||
const unsigned char *inBuffer = (const unsigned char *)aSrc;
|
||||
PRInt32 destBytesPerRow;
|
||||
PRInt32 size = 0;
|
||||
unsigned char *outBuffer = (unsigned char *)NULL;
|
||||
|
||||
printf("scaling image from %dx%d to %dx%d\n", aSrcWidth, aSrcHeight, aDWidth, aDHeight);
|
||||
printf("source: (%d,%d) -- dest: (%d,%d)\n", aSX, aSY, aDX, aDY);
|
||||
|
||||
destBytesPerRow = (aDWidth * 24) >> 5;
|
||||
if ((aDWidth * 3) & 0x1F) {
|
||||
destBytesPerRow++;
|
||||
}
|
||||
destBytesPerRow <<= 2;
|
||||
|
||||
size = destBytesPerRow * aDHeight;
|
||||
|
||||
printf("making buffer for dest... %d bytes\n", size);
|
||||
|
||||
outBuffer = (unsigned char *)PR_Calloc(size, 1);
|
||||
if (!outBuffer)
|
||||
return PR_FALSE;
|
||||
|
||||
pixops_scale_nearest(outBuffer, /* out buffer */
|
||||
0, 0, /* dest_x, dest_y */
|
||||
aDWidth, aDHeight, /* dest_width, dest_height */
|
||||
destBytesPerRow, 3, /* dest_row_stride, dest_num_chans */
|
||||
inBuffer, /* in buffer */
|
||||
aSrcWidth, aSrcHeight, /* src_width, src_height */
|
||||
aBytesPerRow, 3, /* src_row_stride, src_num_chans */
|
||||
(double)aSrcWidth / (double)aDWidth, /* scale_x */
|
||||
(double)aSrcHeight / (double)aDHeight); /* scale_y */
|
||||
|
||||
|
||||
xlib_draw_rgb_image(aDest, aGC,
|
||||
aDX, aDY, aDWidth, aDHeight,
|
||||
XLIB_RGB_DITHER_MAX,
|
||||
outBuffer, destBytesPerRow);
|
||||
PR_Free(outBuffer);
|
||||
|
||||
return PR_TRUE;
|
||||
}
|
Загрузка…
Ссылка в новой задаче