/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*- * ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0/LGPL 2.1 * * 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 Corporation code. * * The Initial Developer of the Original Code is Mozilla Foundation. * Portions created by the Initial Developer are Copyright (C) 2007 * the Initial Developer. All Rights Reserved. * * Contributor(s): * Vladimir Vukicevic * * Alternatively, the contents of this file may be used under the terms of * either the GNU General Public License Version 2 or later (the "GPL"), or * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), * in which case the provisions of the GPL or the LGPL are applicable instead * of those above. If you wish to allow use of your version of this file only * under the terms of either the GPL or the LGPL, and not to allow others to * use your version of this file under the terms of the MPL, indicate your * decision by deleting the provisions above and replace them with the notice * and other provisions required by the GPL or the LGPL. If you do not delete * the provisions above, a recipient may use your version of this file under * the terms of any one of the MPL, the GPL or the LGPL. * * ***** END LICENSE BLOCK ***** */ #include "nsCOMPtr.h" #include "nsTArray.h" #include "nsString.h" #include "nsDependentString.h" #include "prinrval.h" #include "gfxContext.h" #include "gfxFont.h" #include "gfxPlatform.h" #include "gfxFontTest.h" #include "gfxTextRunWordCache.h" #if defined(XP_MACOSX) #include "gfxTestCocoaHelper.h" #endif #ifdef MOZ_WIDGET_GTK2 #include "gtk/gtk.h" #endif class FrameTextRunCache; static FrameTextRunCache *gTextRuns = nsnull; /* * Cache textruns and expire them after 3*10 seconds of no use. */ class FrameTextRunCache : public nsExpirationTracker { public: enum { TIMEOUT_SECONDS = 10 }; FrameTextRunCache() : nsExpirationTracker(TIMEOUT_SECONDS*1000) {} ~FrameTextRunCache() { AgeAllGenerations(); } void RemoveFromCache(gfxTextRun* aTextRun) { if (aTextRun->GetExpirationState()->IsTracked()) { RemoveObject(aTextRun); } gfxTextRunWordCache::RemoveTextRun(aTextRun); } // This gets called when the timeout has expired on a gfxTextRun virtual void NotifyExpired(gfxTextRun* aTextRun) { RemoveFromCache(aTextRun); delete aTextRun; } }; static gfxTextRun * MakeTextRun(const PRUnichar *aText, PRUint32 aLength, gfxFontGroup *aFontGroup, const gfxFontGroup::Parameters* aParams, PRUint32 aFlags) { nsAutoPtr textRun; if (aLength == 0) { textRun = aFontGroup->MakeEmptyTextRun(aParams, aFlags); } else if (aLength == 1 && aText[0] == ' ') { textRun = aFontGroup->MakeSpaceTextRun(aParams, aFlags); } else { textRun = gfxTextRunWordCache::MakeTextRun(aText, aLength, aFontGroup, aParams, aFlags); } if (!textRun) return nsnull; nsresult rv = gTextRuns->AddObject(textRun); if (NS_FAILED(rv)) { gTextRuns->RemoveFromCache(textRun); return nsnull; } return textRun.forget(); } already_AddRefed MakeContext () { const int size = 200; nsRefPtr surface; surface = gfxPlatform::GetPlatform()-> CreateOffscreenSurface(gfxIntSize(size, size), gfxASurface::ContentFromFormat(gfxASurface::ImageFormatRGB24)); gfxContext *ctx = new gfxContext(surface); NS_IF_ADDREF(ctx); return ctx; } int main (int argc, char **argv) { #ifdef MOZ_WIDGET_GTK2 gtk_init(&argc, &argv); #endif #ifdef XP_MACOSX CocoaPoolInit(); #endif // Initialize XPCOM nsresult rv = NS_InitXPCOM2(nsnull, nsnull, nsnull); if (NS_FAILED(rv)) return -1; rv = gfxPlatform::Init(); if (NS_FAILED(rv)) return -1; // let's get all the xpcom goop out of the system fflush (stderr); fflush (stdout); gTextRuns = new FrameTextRunCache(); nsRefPtr ctx = MakeContext(); { gfxFontStyle style (FONT_STYLE_NORMAL, NS_FONT_STRETCH_NORMAL, 139, 10.0, NS_NewPermanentAtom(NS_LITERAL_STRING("en")), 0.0, false, false, false, NS_LITERAL_STRING(""), NS_LITERAL_STRING("")); nsRefPtr fontGroup = gfxPlatform::GetPlatform()->CreateFontGroup(NS_LITERAL_STRING("Geneva, MS Sans Serif, Helvetica,serif"), &style, nsnull); gfxTextRunFactory::Parameters params = { ctx, nsnull, nsnull, nsnull, 0, 60 }; PRUint32 flags = gfxTextRunFactory::TEXT_IS_PERSISTENT; // First load an Arabic word into the cache const char cString[] = "\xd8\xaa\xd9\x85"; nsDependentCString cStr(cString); NS_ConvertUTF8toUTF16 str(cStr); gfxTextRun *tr = MakeTextRun(str.get(), str.Length(), fontGroup, ¶ms, flags); tr->GetAdvanceWidth(0, str.Length(), nsnull); // Now try to trigger an assertion with a word cache bug. The first // word is in the cache so it gets added to the new textrun directly. // The second word is not in the cache const char cString2[] = "\xd8\xaa\xd9\x85\n\xd8\xaa\xd8\x85 "; nsDependentCString cStr2(cString2); NS_ConvertUTF8toUTF16 str2(cStr2); gfxTextRun *tr2 = MakeTextRun(str2.get(), str2.Length(), fontGroup, ¶ms, flags); tr2->GetAdvanceWidth(0, str2.Length(), nsnull); } fflush (stderr); fflush (stdout); }