app_server: keep pinned fonts accessible by ID after removal

On font removal styles may still be referenced by views, pictures or
whatever else. In that case, what we were doing had the following
effects:
- The style is still available through the family. So it is still
  returned when listing fonts.
- The style is not available by ID. So a few app server messages will
  fail, including those for string width or character escapements.
Moreover, if the removal was due to an update, adding the style again
fails because we already have one by that name. If all the old
references are finally dropped, we end up without the old nor the
updated style.

We now do the opposite: until all references are dropped, a style can
still be fetched by ID (that is, by an object that loaded it before
being removed), but it is not listed anymore (so it won't be given to an
app loading a font by name or by changing the style of a font of the
same family).

Fixes: #18868
Change-Id: Ia64744afeb9297fd446e437d08636733b6dc0aec
Reviewed-on: https://review.haiku-os.org/c/haiku/+/7633
Reviewed-by: Fredrik Holmqvist <fredrik.holmqvist@gmail.com>
Reviewed-by: Adrien Destugues <pulkomandy@pulkomandy.tk>
Tested-by: Commit checker robot <no-reply+buildbot@haiku-os.org>
Haiku-Format: Haiku-format Bot <no-reply+haikuformatbot@haiku-os.org>
Reviewed-by: waddlesplash <waddlesplash@gmail.com>
This commit is contained in:
Máximo Castañeda 2024-04-12 20:32:20 +02:00 committed by waddlesplash
parent 31e7087b07
commit 0b8508801b
6 changed files with 55 additions and 37 deletions

View File

@ -2014,7 +2014,7 @@ ServerApp::_DispatchMessage(int32 code, BPrivate::LinkReceiver& link)
// 1) font_family - name of font family to use
// 2) font_style - name of style in family
// 3) family ID - only used if 1) is empty
// 4) style ID - only used if 2) is empty
// 4) style ID - only used if 1) and 2) are empty
// 5) face - the font's current face
// Returns:

View File

@ -135,8 +135,6 @@ FontFamily::RemoveStyle(FontStyle* style)
if (!fStyles.RemoveItem(style))
return false;
style->_SetFontFamily(NULL, -1);
// force a refresh if a request for font flags is needed
fFlags = kInvalidFamilyFlags;
return true;
@ -239,20 +237,6 @@ FontFamily::GetStyle(const char *name) const
}
FontStyle*
FontFamily::GetStyleByID(uint16 id) const
{
int32 count = fStyles.CountItems();
for (int32 i = 0; i < count; i++) {
FontStyle* style = fStyles.ItemAt(i);
if (style->ID() == id)
return style;
}
return NULL;
}
FontStyle*
FontFamily::GetStyleMatchingFace(uint16 face) const
{

View File

@ -35,7 +35,6 @@ public:
FontStyle* GetStyle(const char* style) const;
FontStyle* GetStyleMatchingFace(uint16 face) const;
FontStyle* GetStyleByID(uint16 face) const;
uint16 ID() const
{ return fID; }

View File

@ -204,7 +204,11 @@ FontManager::GetStyle(uint16 familyID, uint16 styleID) const
ASSERT(IsLocked());
FontKey key(familyID, styleID);
return fStyleHashTable.Get(key);
FontStyle* style = fStyleHashTable.Get(key);
if (style != NULL)
return style;
return fDelistedStyleHashTable.Get(key);
}
@ -214,7 +218,7 @@ FontManager::GetStyle(uint16 familyID, uint16 styleID) const
\param family The font's family or NULL in which case \a familyID is used
\param style The font's style or NULL in which case \a styleID is used
\param familyID will only be used if \a family is NULL (or empty)
\param styleID will only be used if \a style is NULL (or empty)
\param styleID will only be used if \a family and \a style are NULL (or empty)
\param face is used to specify the style if both \a style is NULL or empty
and styleID is 0xffff.
@ -228,6 +232,11 @@ FontManager::GetStyle(const char* familyName, const char* styleName,
FontFamily* family;
if (styleID != 0xffff && (familyName == NULL || !familyName[0])
&& (styleName == NULL || !styleName[0])) {
return GetStyle(familyID, styleID);
}
// find family
if (familyName != NULL && familyName[0])
@ -243,9 +252,6 @@ FontManager::GetStyle(const char* familyName, const char* styleName,
if (styleName != NULL && styleName[0])
return family->GetStyle(styleName);
if (styleID != 0xffff)
return family->GetStyleByID(styleID);
// try to get from face
return family->GetStyleMatchingFace(face);
}
@ -283,15 +289,15 @@ FontManager::RemoveStyle(FontStyle* style)
if (family == NULL)
debugger("family is NULL!");
FontStyle* check = GetStyle(family->ID(), style->ID());
if (check != NULL)
debugger("style removed but still available!");
fDelistedStyleHashTable.Remove(FontKey(family->ID(), style->ID()));
int count = fDelistedFamilies.Get(family) - 1;
if (count == 0)
fDelistedFamilies.Remove(family);
else if (count > 0)
fDelistedFamilies.Put(family, count);
if (family->RemoveStyle(style)
&& family->CountStyles() == 0) {
fFamilies.RemoveItem(family);
if (family->CountStyles() == 0 && !fDelistedFamilies.ContainsKey(family))
delete family;
}
}
@ -351,16 +357,37 @@ FontManager::_RemoveFont(uint16 familyID, uint16 styleID)
{
ASSERT(IsLocked());
return fStyleHashTable.Remove(FontKey(familyID, styleID));
FontKey key(familyID, styleID);
FontStyle* style = fStyleHashTable.Get(key);
if (style != NULL) {
fDelistedStyleHashTable.Put(key, style);
FontFamily* family = style->Family();
fDelistedFamilies.Put(family, fDelistedFamilies.Get(family) + 1);
if (family->RemoveStyle(style) && family->CountStyles() == 0)
fFamilies.RemoveItem(family);
fStyleHashTable.Remove(key);
}
return style;
}
void
FontManager::_RemoveAllFonts()
{
for (int32 i = fFamilies.CountItems(); i-- > 0;)
delete fFamilies.RemoveItemAt(i);
for (int32 i = fFamilies.CountItems(); i-- > 0;) {
FontFamily* family = fFamilies.RemoveItemAt(i);
fDelistedFamilies.Remove(family);
delete family;
}
HashMap<FontKey, FontStyle*>::Iterator it = fDelistedStyleHashTable.GetIterator();
while (it.HasNext()) {
FontFamily* family = it.Next().value->Family();
fDelistedFamilies.Remove(family);
delete family;
}
fDelistedFamilies.Clear();
fStyleHashTable.Clear();
}

View File

@ -79,6 +79,9 @@ protected:
private:
struct FontKey {
FontKey()
: familyID(0xffff), styleID(0xffff) {}
FontKey(uint16 family, uint16 style)
: familyID(family), styleID(style) {}
@ -99,8 +102,11 @@ private:
private:
typedef BObjectList<FontFamily> FamilyList;
FamilyList fFamilies;
HashMap<HashKeyPointer<FontFamily*>, int>
fDelistedFamilies;
HashMap<FontKey, BReference<FontStyle> > fStyleHashTable;
HashMap<FontKey, FontStyle*> fDelistedStyleHashTable;
uint16 fNextID;
};

View File

@ -571,7 +571,7 @@ GlobalFontManager::GetStyle(uint16 familyID, uint16 styleID) const
\param family The font's family or NULL in which case \a familyID is used
\param style The font's style or NULL in which case \a styleID is used
\param familyID will only be used if \a family is NULL (or empty)
\param styleID will only be used if \a style is NULL (or empty)
\param styleID will only be used if \a family and \a style are NULL (or empty)
\param face is used to specify the style if both \a style is NULL or empty
and styleID is 0xffff.
@ -585,6 +585,11 @@ GlobalFontManager::GetStyle(const char* familyName, const char* styleName,
FontFamily* family;
if (styleID != 0xffff && (familyName == NULL || !familyName[0])
&& (styleName == NULL || !styleName[0])) {
return GetStyle(familyID, styleID);
}
// find family
if (familyName != NULL && familyName[0])
@ -613,9 +618,6 @@ GlobalFontManager::GetStyle(const char* familyName, const char* styleName,
return family->GetStyle(styleName);
}
if (styleID != 0xffff)
return family->GetStyleByID(styleID);
// try to get from face
return family->GetStyleMatchingFace(face);
}