From b6a3282ea84c9b0ca93d298d2560d1ffc130d3f7 Mon Sep 17 00:00:00 2001
From: Mingye Wang <arthur200126@gmail.com>
Date: Wed, 21 Feb 2018 19:03:23 -0500
Subject: [PATCH] Correct score selection in FcFontSetMatchInternal

FcFontSetMatchInternal was using the strength of the first element in
deciding which score to use. This is wrong as we should look at the
priority instead.

Instead of building two scores to choose from, we now only use one
score variable and decide whether it should be used for strong, weak,
or both by testing for matcher->{strong,weak} == priority. Doing so
ensures perfect emulation of FcCompare() behavior for each priority.

Fixes michalsrb/fontconfig#2.

A previous version of this commit decided between a strong and a weak
score by testing for matcher->strong == priority. This fix is
incomplete: for priorities that share the same value for strong and
weak, FcCompareValueList would use the smaller of those two when called
by FcCompare as two pointers to "score" coincide; the previous fix does
not similate this feature.
---
 src/fcmatch.c | 13 +++++++++----
 1 file changed, 9 insertions(+), 4 deletions(-)

diff --git a/src/fcmatch.c b/src/fcmatch.c
index a2c9eb13..da242048 100644
--- a/src/fcmatch.c
+++ b/src/fcmatch.c
@@ -937,6 +937,13 @@ FcFontSetMatchInternal (FcFontSet   **sets,
 	FcBitsetClear(best_matches_so_far, FcFalse);
 	double best_score_so_far = 1e99;
 
+	// For each priority we are only interested in getting one score.
+	// Its strength is only determinied by the priority, so do it right now.
+	double score = 0.0;
+	double *value_strong = (matcher->strong == priority) ? &score : NULL;
+	double *value_weak = (matcher->weak == priority) ? &score : NULL;
+	assert(value_strong || value_weak);
+
 	// Iterate over all fonts in all sets
 	for (set = 0, index = 0; set < nsets; set++)
 	{
@@ -955,14 +962,14 @@ FcFontSetMatchInternal (FcFontSet   **sets,
 
 		// Compare the font's value lists to the pattern's value list and measure distance.
 		// If the font doesn't contain such object, it is considered as distance 0 (best).
-		double score_strong = 0.0, score_weak = 0.0;
+		score = 0.0;
 		const FcPatternElt *font_elt = FcPatternObjectFindElt(font, matcher->object);
 		if (font_elt)
 		{
 		    if (!FcCompareValueList (matcher->object, matcher,
 					    FcPatternEltValues(p_elt),
 					    FcPatternEltValues(font_elt),
-					    NULL, &score_strong, &score_weak,
+					    NULL, value_strong, value_weak,
 					    NULL, result))
 		    {
 			best = NULL;
@@ -970,8 +977,6 @@ FcFontSetMatchInternal (FcFontSet   **sets,
 		    }
 		}
 
-		double score = (FcPatternEltValues(p_elt)->binding == FcValueBindingStrong ? score_strong : score_weak);
-
 		// If this font was better match than the best so far, forget them and remember new best.
 		if (score < best_score_so_far)
 		{