Checking in Cairo code that gets things into a barely-usable state. http://weblogs.mozillazine.org/roc/archives/2005/04/glimpse_of_the.html Not Part Of The Build

This commit is contained in:
roc+%cs.cmu.edu 2005-04-21 23:51:53 +00:00
Родитель 800b238475
Коммит 1acf9f8782
8 изменённых файлов: 243 добавлений и 147 удалений

Просмотреть файл

@ -99,6 +99,7 @@ EXTRA_DSO_LDOPTS += \
$(EXTRA_DSO_LIBS) \
$(MOZ_COMPONENT_LIBS) \
$(MOZ_UNICHARUTIL_LIBS) \
$(MOZ_CAIRO_LIBS) \
$(MOZ_JS_LIBS) \
$(TK_LIBS) \
$(NULL)

Просмотреть файл

@ -109,8 +109,6 @@ nsCairoDeviceContext::nsCairoDeviceContext()
mZoom = 1.0f;
mTextZoom = 1.0f;
mSurfaceManager = nsnull;
#ifdef MOZ_ENABLE_XLIB
mXlibRgbHandle = xxlib_find_handle(XXLIBRGB_DEFAULT_HANDLE);
#endif
@ -118,7 +116,6 @@ nsCairoDeviceContext::nsCairoDeviceContext()
nsCairoDeviceContext::~nsCairoDeviceContext()
{
delete mSurfaceManager;
}
int
@ -162,8 +159,6 @@ nsCairoDeviceContext::Init(nsNativeWidget aWidget)
mWidth = -1;
mHeight = -1;
mSurfaceManager = new nsCairoSurfaceManager();
return NS_OK;
}

Просмотреть файл

@ -58,8 +58,6 @@
#include "xlibrgb.h"
#endif
class nsCairoSurfaceManager;
class nsCairoDeviceContext : public DeviceContextImpl
{
public:
@ -120,8 +118,6 @@ public:
Drawable GetXPixmapParentDrawable();
#endif
nsCairoSurfaceManager *GetSurfaceManager() { return mSurfaceManager; }
private:
nsNativeWidget mWidget;
@ -132,8 +128,6 @@ private:
PRInt32 mWidth;
PRInt32 mHeight;
nsCairoSurfaceManager *mSurfaceManager;
#if defined(MOZ_ENABLE_GTK2) || defined(MOZ_ENABLE_XLIB)
Drawable mPixmapParentDrawable;
#endif

Просмотреть файл

@ -45,11 +45,52 @@
#include "nsIServiceManager.h"
static void ARGBToThreeChannel(PRUint32* aARGB, PRUint8* aData) {
PRUint8 r = (PRUint8)(*aARGB >> 16);
PRUint8 g = (PRUint8)(*aARGB >> 8);
PRUint8 b = (PRUint8)*aARGB;
#if defined(XP_WIN) || defined(XP_OS2) || defined(XP_BEOS) || defined(MOZ_WIDGET_PHOTON)
// BGR format; assume little-endian system
#ifndef IS_LITTLE_ENDIAN
#error Strange big-endian/OS combination
#endif
// BGR, blue byte first
aData[0] = b; aData[1] = g; aData[2] = r;
#else
// RGB, red byte first
aData[0] = r; aData[1] = g; aData[2] = b;
#endif
}
static void ThreeChannelToARGB(PRUint8* aData, PRUint32* aARGB) {
PRUint32 v = *aARGB & 0xFF000000;
PRUint8 r, g, b;
#if defined(XP_WIN) || defined(XP_OS2) || defined(XP_BEOS) || defined(MOZ_WIDGET_PHOTON)
// BGR format; assume little-endian system
#ifndef IS_LITTLE_ENDIAN
#error Strange big-endian/OS combination
#endif
// BGR, blue byte first
b = aData[0]; g = aData[1]; r = aData[2];
#else
// RGB, red byte first
r = aData[0]; g = aData[1]; b = aData[2];
#endif
v |= (r << 16) | (g << 8) | b;
*aARGB = v;
}
nsCairoImage::nsCairoImage()
: mWidth(0),
mHeight(0),
mDecoded(0,0,0,0),
mImageSurface(nsnull),
mImageSurfaceData(nsnull)
mImageSurfaceBuf(nsnull),
mImageSurfaceData(nsnull),
mImageSurfaceAlpha(nsnull),
mAlphaDepth(0),
mHadAnyAlphaValues(PR_FALSE),
mHadAnyPixelValues(PR_FALSE)
{
}
@ -59,6 +100,8 @@ nsCairoImage::~nsCairoImage()
cairo_surface_destroy(mImageSurface);
// XXXX - totally not safe. mImageSurface should own data,
// but it doesn't.
if (mImageSurfaceBuf)
nsMemory::Free(mImageSurfaceBuf);
if (mImageSurfaceData)
nsMemory::Free(mImageSurfaceData);
if (mImageSurfaceAlpha)
@ -69,7 +112,6 @@ NS_IMPL_ISUPPORTS1(nsCairoImage, nsIImage)
//////////////////////////////////////////////
//// nsIImage
nsresult
nsCairoImage::Init(PRInt32 aWidth, PRInt32 aHeight, PRInt32 aDepth, nsMaskRequirements aMaskRequirements)
{
@ -79,31 +121,36 @@ nsCairoImage::Init(PRInt32 aWidth, PRInt32 aHeight, PRInt32 aDepth, nsMaskRequir
switch(aMaskRequirements)
{
case nsMaskRequirements_kNeeds1Bit:
mAlphaDepth = 1;
mCairoFormat = CAIRO_FORMAT_ARGB32;
break;
case nsMaskRequirements_kNeeds8Bit:
mAlphaDepth = 8;
mCairoFormat = CAIRO_FORMAT_ARGB32;
break;
default:
mAlphaDepth = 0;
// this should be able to be RGB24, but that doesn't seem to work
mCairoFormat = CAIRO_FORMAT_ARGB32;
break;
}
if (aDepth == 24 || aDepth == 32) {
mImageSurfaceData = (char *) nsMemory::Alloc(aWidth * aHeight * 4);
mImageSurfaceAlpha = (char *) nsMemory::Alloc(aWidth * aHeight);
mImageSurface = cairo_image_surface_create_for_data
(mImageSurfaceData,
CAIRO_FORMAT_ARGB32,
mWidth,
mHeight,
aWidth * 4);
}
PRInt32 size = aWidth*aHeight*4;
mImageSurfaceBuf = (PRUint32*)nsMemory::Alloc(size);
// Fill it in. Setting alpha to FF is important for images with no
// alpha of their own
memset(mImageSurfaceBuf, 0xFF, size);
mImageSurface = cairo_image_surface_create_for_data
((char*)mImageSurfaceBuf, mCairoFormat, mWidth, mHeight, aWidth * 4);
return NS_OK;
}
PRInt32
nsCairoImage::GetBytesPix()
{
return 4;
// not including alpha, I guess
return 3;
}
PRBool
@ -133,41 +180,37 @@ nsCairoImage::GetBits()
PRInt32
nsCairoImage::GetLineStride()
{
return mWidth * 4;
return mWidth*3;
}
PRBool
nsCairoImage::GetHasAlphaMask()
{
/* imglib is such a piece of crap! */
return PR_TRUE;
return mAlphaDepth > 0;
}
PRUint8 *
nsCairoImage::GetAlphaBits()
{
/* eugh */
/* imglib is such a piece of crap! */
return (PRUint8 *) mImageSurfaceAlpha;
}
PRInt32
nsCairoImage::GetAlphaLineStride()
{
/* imglib is such a piece of crap! */
return mWidth;
return mAlphaDepth == 1 ? (mWidth+7)/8 : mWidth;
}
void
nsCairoImage::ImageUpdated(nsIDeviceContext *aContext, PRUint8 aFlags, nsRect *aUpdateRect)
{
mDecoded.UnionRect(mDecoded, *aUpdateRect);
}
PRBool
nsCairoImage::GetIsImageComplete()
{
/* TODO: nsCairoImage needs to store coords of decoded data */
return PR_TRUE;
return mDecoded == nsRect(0, 0, mWidth, mHeight);
}
nsresult
@ -207,30 +250,21 @@ nsCairoImage::Draw(nsIRenderingContext &aContext, nsIDrawingSurface *aSurface,
cairo_t *dstCairo = cairoContext->GetCairo();
cairo_save(dstCairo);
// just in case this needs setting
cairo_set_target_surface(dstCairo, dstSurf->GetCairoSurface());
// the coords here are absolute
cairo_identity_matrix(dstCairo);
// clip to target
cairo_rectangle(dstCairo, double(aDX), double(aDY), double(aDWidth), double(aDHeight));
cairo_clip(dstCairo);
// scale up to the size difference
cairo_scale(dstCairo, double(aDWidth)/double(aSWidth), double(aDHeight)/double(aSHeight));
// move to where we need to start the image rectangle, so that
// it gets clipped to the right place
cairo_translate(dstCairo, double(aDX - aSX), double(aDY - aSY));
// show it
cairo_show_surface (dstCairo, mImageSurface, mWidth, mHeight);
cairo_restore(dstCairo);
cairo_pattern_t *pat = cairo_pattern_create_for_surface (mImageSurface);
cairo_matrix_t* matrix = cairo_matrix_create();
if (matrix) {
cairo_matrix_set_affine(matrix, double(aSWidth)/aDWidth, 0,
0, double(aSHeight)/aDHeight, aSX, aSY);
cairo_pattern_set_matrix(pat, matrix);
cairo_matrix_destroy(matrix);
}
cairo_set_pattern (dstCairo, pat);
cairo_pattern_destroy (pat);
cairo_new_path(dstCairo);
cairo_rectangle (dstCairo, aDX, aDY, aDWidth, aDHeight);
cairo_fill (dstCairo);
return NS_OK;
}
@ -243,8 +277,6 @@ nsCairoImage::DrawTile(nsIRenderingContext &aContext,
{
if (aPadX || aPadY)
fprintf (stderr, "Warning: nsCairoImage::DrawTile given padX(%d)/padY(%d), ignoring\n", aPadX, aPadY);
if (aSXOffset || aSYOffset)
fprintf (stderr, "Warning: nsCairoImage::DrawTile given XOffset(%d)/YOffset(%d), ignoring\n", aSXOffset, aSYOffset);
nsCairoDrawingSurface *dstSurf = NS_STATIC_CAST(nsCairoDrawingSurface*, aSurface);
nsCairoRenderingContext *cairoContext = NS_STATIC_CAST(nsCairoRenderingContext*, &aContext);
@ -261,9 +293,18 @@ nsCairoImage::DrawTile(nsIRenderingContext &aContext,
cairo_pattern_t *pat = cairo_pattern_create_for_surface (mImageSurface);
cairo_pattern_set_extend (pat, CAIRO_EXTEND_REPEAT);
if (aSXOffset != 0 || aSYOffset != 0) {
cairo_matrix_t* matrix = cairo_matrix_create();
if (matrix) {
cairo_matrix_set_affine(matrix, 1, 0, 0, 1, aSXOffset, aSYOffset);
cairo_pattern_set_matrix(pat, matrix);
cairo_matrix_destroy(matrix);
}
}
cairo_set_pattern (dstCairo, pat);
cairo_pattern_destroy (pat);
cairo_new_path(dstCairo);
cairo_rectangle (dstCairo, aTileRect.x, aTileRect.y, aTileRect.width, aTileRect.height);
cairo_fill (dstCairo);
@ -303,7 +344,7 @@ nsCairoImage::DrawToImage(nsIImage* aDstImage, PRInt32 aDX, PRInt32 aDY, PRInt32
PRInt8
nsCairoImage::GetAlphaDepth()
{
return 8;
return mAlphaDepth;
}
void *
@ -315,11 +356,106 @@ nsCairoImage::GetBitInfo()
NS_IMETHODIMP
nsCairoImage::LockImagePixels(PRBool aMaskPixels)
{
PRInt32 count = mWidth*mHeight;
if (aMaskPixels) {
NS_ASSERTION(!mImageSurfaceAlpha, "already locked alphas");
NS_ASSERTION(mAlphaDepth == 1 || mAlphaDepth == 8,
"Bad alpha depth");
PRInt32 size = mHeight*(mAlphaDepth == 1 ? ((mWidth+7)/8) : mWidth);
mImageSurfaceAlpha = (PRUint8*)nsMemory::Alloc(size);
if (!mImageSurfaceAlpha)
return NS_ERROR_OUT_OF_MEMORY;
if (mHadAnyAlphaValues) {
// fill from existing ARGB buffer
if (mAlphaDepth == 8) {
for (PRInt32 i = 0; i < count; ++i) {
mImageSurfaceAlpha[i] = (PRUint8)(mImageSurfaceBuf[i] >> 24);
}
} else {
PRInt32 i = 0;
for (PRInt32 row = 0; row < mHeight; ++row) {
PRUint8 alphaBits = 0;
for (PRInt32 col = 0; col < mWidth; ++col) {
PRUint8 mask = 1 << (7 - (col&7));
if (mImageSurfaceBuf[row*mWidth + col] & 0xFF000000) {
alphaBits |= mask;
}
if (mask == 0x01) {
// This mask byte is complete, write it back
mImageSurfaceAlpha[i] = alphaBits;
alphaBits = 0;
++i;
}
}
if (mWidth & 7) {
// write back the incomplete alpha mask
mImageSurfaceAlpha[i] = alphaBits;
++i;
}
}
}
}
} else {
NS_ASSERTION(!mImageSurfaceData, "already locked pixels");
mImageSurfaceData = (PRUint8*)nsMemory::Alloc(mWidth * mHeight * 3);
if (!mImageSurfaceData)
return NS_ERROR_OUT_OF_MEMORY;
if (mHadAnyPixelValues) {
// fill from existing ARGB buffer
for (PRInt32 i = 0; i < count; ++i) {
ARGBToThreeChannel(&mImageSurfaceBuf[i], &mImageSurfaceData[i*3]);
}
}
}
return NS_OK;
}
NS_IMETHODIMP
nsCairoImage::UnlockImagePixels(PRBool aMaskPixels)
{
PRInt32 count = mWidth*mHeight;
if (aMaskPixels) {
NS_ASSERTION(mImageSurfaceAlpha, "alpha values not locked");
NS_ASSERTION(mAlphaDepth == 1 || mAlphaDepth == 8,
"Bad alpha depth");
if (mAlphaDepth == 8) {
for (PRInt32 i = 0; i < count; ++i) {
PRInt32 v = mImageSurfaceBuf[i] & 0xFFFFFF;
v |= mImageSurfaceAlpha[i] << 24;
mImageSurfaceBuf[i] = v;
}
} else {
PRInt32 i = 0;
for (PRInt32 row = 0; row < mHeight; ++row) {
for (PRInt32 col = 0; col < mWidth; ++col) {
PRInt32 index = row*mWidth + col;
PRInt32 v = mImageSurfaceBuf[index] & 0xFFFFFF;
PRUint8 mask = 1 << (7 - (col&7));
if (mImageSurfaceAlpha[i] & mask) {
v |= 0xFF000000;
}
mImageSurfaceBuf[index] = v;
if (mask == 0x01) {
++i;
}
}
if (mWidth & 7) {
++i;
}
}
}
nsMemory::Free(mImageSurfaceAlpha);
mImageSurfaceAlpha = nsnull;
mHadAnyAlphaValues = PR_TRUE;
} else {
NS_ASSERTION(mImageSurfaceData, "had not locked pixels");
for (PRInt32 i = 0; i < count; ++i) {
ThreeChannelToARGB(&mImageSurfaceData[i*3], &mImageSurfaceBuf[i]);
}
nsMemory::Free(mImageSurfaceData);
mImageSurfaceData = nsnull;
mHadAnyPixelValues = PR_TRUE;
}
return NS_OK;
}

Просмотреть файл

@ -91,10 +91,19 @@ public:
protected:
PRInt32 mWidth;
PRInt32 mHeight;
nsRect mDecoded;
cairo_surface_t *mImageSurface;
char *mImageSurfaceData;
char *mImageSurfaceAlpha;
cairo_format_t mCairoFormat;
// Where the mImageSurface data lives (in the mCairoFormat)
PRUint32* mImageSurfaceBuf;
// Where gfxIImageFrame data lives temporarily during LockImagePixels
PRUint8* mImageSurfaceData;
PRUint8* mImageSurfaceAlpha;
PRUint8 mAlphaDepth;
PRPackedBool mHadAnyAlphaValues;
PRPackedBool mHadAnyPixelValues;
};
#endif // NSCAIROIMAGE__H__

Просмотреть файл

@ -91,9 +91,9 @@ nsCairoRenderingContext::Init(nsIDeviceContext* aContext, nsIWidget *aWidget)
mDeviceContext = aContext;
mWidget = aWidget;
nsCOMPtr<nsIDrawingSurface> ids;
cairoDC->GetSurfaceManager()->GetDrawingSurfaceForWidget (cairoDC, aWidget, getter_AddRefs(ids));
mDrawingSurface = ((nsCairoDrawingSurface*) (ids.get()));
mDrawingSurface = new nsCairoDrawingSurface();
nsNativeWidget nativeWidget = aWidget->GetNativeData(NS_NATIVE_WIDGET);
mDrawingSurface->Init (cairoDC, nativeWidget);
mCairo = cairo_create ();
cairo_set_target_surface (mCairo, mDrawingSurface->GetCairoSurface());
@ -200,6 +200,20 @@ nsCairoRenderingContext::GetDrawingSurface(nsIDrawingSurface **aSurface)
return NS_OK;
}
NS_IMETHODIMP
nsCairoRenderingContext::PushTranslation(PushedTranslation* aState)
{
// XXX this is slow!
PushState();
}
NS_IMETHODIMP
nsCairoRenderingContext::PopTranslation(PushedTranslation* aState)
{
// XXX this is slow!
PopState();
}
NS_IMETHODIMP
nsCairoRenderingContext::GetHints(PRUint32& aResult)
{
@ -249,7 +263,7 @@ nsCairoRenderingContext::DoCairoClip()
cairo_init_clip (mCairo);
float pixToTwip = mDeviceContext->DevUnitsToTwips();
float pixToTwip = mDeviceContext->DevUnitsToAppUnits();
if (cplx == eRegionComplexity_rect) {
PRInt32 x, y, w, h;
@ -836,38 +850,6 @@ nsCairoRenderingContext::DrawImage(imgIContainer *aImage,
const nsRect &aSrcRect,
const nsRect &aDestRect)
{
// from nsRenderingContextImpl.cpp
double x,y,w,h;
nsRect dr = aDestRect;
x = dr.x; y = dr.y; w = dr.width; h = dr.height;
cairo_transform_point(mCairo, &x, &y);
cairo_transform_distance(mCairo, &w, &h);
dr.x = (int) x; dr.y = (int) y; dr.width = (int) w; dr.height = (int) h;
nsRect sr = aSrcRect;
x = sr.x; y = sr.y; w = sr.width; h = sr.height;
cairo_transform_point(mCairo, &x, &y);
cairo_transform_distance(mCairo, &w, &h);
sr.x = (int) x; sr.y = (int) y; sr.width = (int) w; sr.height = (int) h;
if (sr.IsEmpty() || dr.IsEmpty())
return NS_OK;
/* What the heck?
* sr.x = aSrcRect.x;
* sr.y = aSrcRect.y;
* mTranMatrix->TransformNoXLateCoord(&sr.x, &sr.y);
*/
x = sr.x;
y = sr.y;
cairo_transform_distance(mCairo, &x, &y);
sr.x = (int) x;
sr.y = (int) y;
/* .. not sure what that's for .. */
nsCOMPtr<gfxIImageFrame> iframe;
aImage->GetCurrentFrame(getter_AddRefs(iframe));
if (!iframe) return NS_ERROR_FAILURE;
@ -875,58 +857,37 @@ nsCairoRenderingContext::DrawImage(imgIContainer *aImage,
nsCOMPtr<nsIImage> img(do_GetInterface(iframe));
if (!img) return NS_ERROR_FAILURE;
nsIDrawingSurface *surface = nsnull;
GetDrawingSurface(&surface);
if (!surface) return NS_ERROR_FAILURE;
// For Bug 87819
// iframe may want image to start at different position, so adjust
nsRect iframeRect;
iframe->GetRect(iframeRect);
if (iframeRect.x > 0) {
// Adjust for the iframe offset before we do scaling.
sr.x -= iframeRect.x;
// aSrcRect is always in appunits, it has
// nothing to do with the current transform
float app2dev;
app2dev = mDeviceContext->AppUnitsToDevUnits();
nsRect sr;
sr.x = NSToIntRound(app2dev*aSrcRect.x);
sr.y = NSToIntRound(app2dev*aSrcRect.y);
sr.width = NSToIntRound(app2dev*aSrcRect.XMost()) - sr.x;
sr.height = NSToIntRound(app2dev*aSrcRect.YMost()) - sr.y;
nsRect dr = aDestRect;
if (iframeRect != sr) {
double xscale = double(aDestRect.width)/sr.width;
double yscale = double(aDestRect.height)/sr.height;
nsRect scaledUpIRect;
scaledUpIRect.x = NSToCoordRound(iframeRect.x*xscale);
scaledUpIRect.y = NSToCoordRound(iframeRect.y*yscale);
scaledUpIRect.width = NSToCoordRound(iframeRect.XMost()*xscale) - scaledUpIRect.x;
scaledUpIRect.height = NSToCoordRound(iframeRect.YMost()*yscale) - scaledUpIRect.y;
nscoord scaled_x = sr.x;
if (dr.width != sr.width) {
PRFloat64 scale_ratio = PRFloat64(dr.width) / PRFloat64(sr.width);
scaled_x = NSToCoordRound(scaled_x * scale_ratio);
}
if (sr.x < 0) {
dr.x -= scaled_x;
sr.width += sr.x;
dr.width += scaled_x;
if (sr.width <= 0 || dr.width <= 0)
return NS_OK;
sr.x = 0;
} else if (sr.x > iframeRect.width) {
return NS_OK;
}
sr.IntersectRect(sr, iframeRect);
dr.IntersectRect(dr, scaledUpIRect);
}
if (iframeRect.y > 0) {
// Adjust for the iframe offset before we do scaling.
sr.y -= iframeRect.y;
nscoord scaled_y = sr.y;
if (dr.height != sr.height) {
PRFloat64 scale_ratio = PRFloat64(dr.height) / PRFloat64(sr.height);
scaled_y = NSToCoordRound(scaled_y * scale_ratio);
}
if (sr.y < 0) {
dr.y -= scaled_y;
sr.height += sr.y;
dr.height += scaled_y;
if (sr.height <= 0 || dr.height <= 0)
return NS_OK;
sr.y = 0;
} else if (sr.y > iframeRect.height) {
return NS_OK;
}
}
return img->Draw(*this, surface, sr.x, sr.y, sr.width, sr.height,
return img->Draw(*this, mDrawingSurface, sr.x - iframeRect.x, sr.y - iframeRect.y,
sr.width, sr.height,
dr.x, dr.y, dr.width, dr.height);
}
@ -964,17 +925,13 @@ nsCairoRenderingContext::DrawTile(imgIContainer *aImage,
nsCOMPtr<nsIImage> img(do_GetInterface(iframe));
if (!img) return NS_ERROR_FAILURE;
nsIDrawingSurface *surface = nsnull;
GetDrawingSurface(&surface);
if (!surface) return NS_ERROR_FAILURE;
/* bug 113561 - frame can be smaller than container */
nsRect iframeRect;
iframe->GetRect(iframeRect);
PRInt32 padx = width - iframeRect.width;
PRInt32 pady = height - iframeRect.height;
return img->DrawTile(*this, surface,
return img->DrawTile(*this, mDrawingSurface,
xOffset - iframeRect.x, yOffset - iframeRect.y,
padx, pady,
dr);

Просмотреть файл

@ -187,6 +187,10 @@ public:
NS_IMETHOD ReleaseBackbuffer(void);
NS_IMETHOD DestroyCachedBackbuffer(void);
NS_IMETHOD UseBackbuffer(PRBool* aUseBackbuffer);
NS_IMETHOD PushTranslation(PushedTranslation* aState);
NS_IMETHOD PopTranslation(PushedTranslation* aState);
#ifdef MOZ_MATHML
NS_IMETHOD GetBoundingMetrics(const char* aString, PRUint32 aLength, nsBoundingMetrics& aBoundingMetrics);
NS_IMETHOD GetBoundingMetrics(const PRUnichar* aString, PRUint32 aLength,

Просмотреть файл

@ -86,7 +86,7 @@ nsCairoSurfaceManager::GetDrawingSurfaceForNativeWidget (nsCairoDeviceContext *a
WidgetToSurfaceMap::iterator iter = mSurfaceMap.find(aWidget);
/* cached? */
if (iter == mSurfaceMap.end()) {
if (PR_TRUE || iter == mSurfaceMap.end()) {
/* nope. */
surf = new nsCairoDrawingSurface();
NS_ADDREF(surf); // our own reference for map